Node.js 前世今生

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

提到 Node.js, 绕不过 JavaScript.

JavaScript

December 4, 1995

SpiderMonkey
Chakra
JavaScriptCore
V8

ry

2009

  • V8 很快, 很专业.
  • V8 是用 C++ 写的.

历史上曾经出现过运行在 JVM 上的 Rhino, .Net 上的 JScript, 以及其他五花八门的实现.

Node.js

Deno

Bun

JavaScript reference

  • Built-ins
  • Statements
  • Expressions and operators
  • Functions
  • Classes
  • Additional reference pages

        /* https://tc39.es */

        @Get('/users') getUsers() {};
      
    
tc39/proposal-do-expressions

        let result = do {
          let v = f();
          v * v + 1
        };
      
tc39/proposal-pipeline-operator

        let data = url
          |> await fetch
          |> await %.json();
      
tc39/proposal-pattern-matching

        const res = await fetch(api);
        match (res) {
          when ({
            status: 200, headers: { 'Content-Length': size }
          }):
            console.log('size is', size);
          when ({ status: 404 }):
            console.log('API not found');
          when ({ status }) if (status >= 400): do {
            throw new RequestError(res);
          }
        };
      

Web API

Web API 是用于开发 Web 时使用的浏览器接口, 它们不是 JavaScript 的必要组成部分. 例如:

  • window.getSelection
  • document.getElementById
  • location.href
  • localStorage
  • fetch
  • console.log

单纯的 JavaScript

没有统一的标准库.

本身没有 IO, 写不出 Hello world.

😅

你离 Node.js 很近

每个前端的电脑上都安装了 Node.js.

很多 JS 代码能在 Node.js 里跑起来.

文件操作

ls

            // #!/usr/bin/env node
            const fs = require('fs/promises');

            const files = await fs.readdir('.')
            const result = files.join('\n');

            console.log(result);
          
      

文件操作

读写文件能做很多事, 例如


      const fs = require('fs/promises');

      fs.readFile('App.jsx');

      // transform code

      fs.writeFile('App.js');
    

JavaScript 版本

ECMAScript 是标准, JavaScript 是实现.

ES3 ES5 ES6
ES2015 ES2016 ... ES2022 ESNext

Babel 可以把高版本代码编译到低版本.

ESNext ES2015

对比其他语言

  • Python/Go 体验新特性需要安装 beta 版.
  • Java 项目往往停留在 JDK8.
  • .Net framework 很大, 安装很慢.

为什么前端需要构建?

  • JS 编译是指语法降级.
  • 压缩节省带宽.
  • 打包是因为 HTTP 2.0 还未普及.

网络请求

http server


              const http = require('http');

              const server = http.createServer((req, res) => {
                const time = new Date();
                const json = JSON.stringify({ time });

                res.statusCode = 200;
                res.setHeader('Content-Type', 'application/json');
                res.end(json);
              });

              server.listen(3000);
            
        

express


              const express = require('express');

              const app = express();

              app.get('/', (req, res) => {
                res.send('<h1>Hello express!</h1>');
              })

              app.listen(3000);
            
        

koa


              const Koa = require('koa');
              const app = new Koa();

              app.use(async ctx => {
                ctx.body = '<h1>Hello koa!</h1>';
              });

              app.listen(3000);
            
        

Nest

nestjs.com

        import { Get, Controller, Render } from '@nestjs/common';
        import { PostsService } from './posts/posts.service';

        @Controller()
        export class AppController {
          constructor(private readonly postsService: PostsService) {}

          @Get('/posts')
          @Render('posts')
          render() {
            const posts = this.postsService.getPosts();
            return { posts };
          }
        }
      

View Templates

把变量塞进模板, 输出 HTML.


        import ejs from 'ejs';

        const template = '<h1>Hello {<%= name %>!</h1>';

        /* <h1>Hello ejs!</h1> */
        ejs.render(template, { name: 'ejs' });
      

拼接字符串? 类似, 但不完全是.


        const name = 'world';

        `<h1>Hello ${name}!</h1>`;
      

ejs 语法


        <!-- 条件 -->
        <% if (user) { %>
          <h2><%= user.name %></h2>
        <% } %>

        <!-- 循环 -->
        <ul>
          <% users.forEach(function(user){ %>
            <!-- 引用 -->
            <%- include('user/show', {user: user}); %>
          <% }); %>
        </ul>
      

pug 语法


        <!-- 缩进 -->
        #root.container.m-auto
          h1.text-red Hello pug!
      

        <div id="root" class="container m-auto">
          <h1 class="text-red">Hello pug!</h1>
        </div>
      

多如牛毛的 template engines


        {
          ejs:      '<h1>Hello {<%= name %>!</h1>',
          pug:      'h1 Hello #{ name }!',
          lodash:   '<% _.forEach(l, function(n) { %><li><%- n %></li><% }); %>',
          mustache: '{{title}} spends {{calc}}',
          nunjucks: '{% block nav %} <h1>{{ logo }}</h1> {% endblock %}'
          react:    '<App title={title} />',
        }
      

Html Webpack Plugin 示例

React template

const App = () => {
  const [value, setValue] = React.useState(0);
  return (
    <button style={{ fontSize: 96 }} onClick={() => setValue(value + 1)}>
      👍<sup>{value}</sup>
    </button>
  );
};

new Koa()
  .use(async (ctx) => {
    ctx.body = `
      <div id="app">${ReactDOMServer.renderToString(<App />)}</div>
    `;
  })
  .listen();

Next

Server Side Rendering