Node.js 与前端开发实战 | 青训营笔记

68 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

Node.js 应用场景

  1. 前端工程化(……)

    1. Bundle webpack、vite、esbuild、parcel
    2. Uglify uglifyjs
    3. Transpile babeljs、typescript
    4. esbuild、parcel、prisma
  2. Web 服务端应用(Node.js、Vercel)

    1. 学习曲线平缓、开发效率高
    2. 运行效率接近常见的编译语言
    3. 社区生态丰富、工具链成熟(npm、V8 inspector)
    4. 与前端结合场景有优势(SSR)
  3. Electron 跨端桌面应用

    1. 商业应用(vscode、slack、discord、zoom)
    2. 大型公司内的效率工具

字节内部

BFF、SSR Modern.js

服务端应用

Electron应用 飞连、飞书

Node.js 运行时结构

Node 结构

  • Node.js Core 由 JavaScript 或 C++ 语言编写
  • N-API 使用其他编程语言(除 JS 和 C++之外)写的模块
  • V8 JavaScript Runtime 及 诊断调试工具 inspector
  • libuv 封装操作系统 API,如 eventloop 事件循环、 syscall 系统调用等
  • nghttp2 http相关
  • zlib 压缩文件相关
  • c-ares DNS 查询相关
  • llhttp http协议解析
  • openSSL ssl加密协议解析

运行时特点

  1. 异步 I/O
  • I/O 操作异步执行
  1. 单线程
  • 实质 JS 线程 + uv 线程池 + V8 任务线程池 + V8 Inspector 线程
  • 不用考虑多线程状态同步问题,能够较高效地利用系统资源
  • 阻塞会产生更多负面影响,可使用多进程或者多线程解决
  1. 跨平台
  • 大多数 API 均跨平台

  • 开发成本较低

编写 HTTP Server

编写 HTTP Server

const http = require('http')

const port = 3000

const server = http.createServer((req, res) => {
   const bufs = []
   req.on('data', (buf) => {
     bufs.push(buf)
   })
   req.on('end', () => {
     try {
       const data = JSON.parse(Buffer.concat(bufs).toString('utf8'))
       res.setHeader('Content-Type', 'application/json')
       res.end(JSON.stringify({
         echo: data.msg || 'Hello',
       }))
     } catch (err) {
       res.end('<h1>invalid json</h1>')
     }
   })
})

server.listen(port, () => {
  console.log(`server listens on: ${port}`)
})

转换为 promise

const http = require('http')

const server = http.createServer((req, res) => {
  const msg = await new Promise((resolve, reject) => {
    const bufs = []
    req.on('data', (buf) => {
      bufs.push(buf)
    })
    req.on('error', (err) => {
      reject(err)
    })
    req.on('end', () => {
      try {
        const data = JSON.parse(Buffer.concat(bufs).toString('utf8'))
        resolve(data.msg)
      } catch (err) {
      	reject(err)
      }
    })
  })

  res.setHeader('Content-Type', 'application/json')
  res.end(JSON.stringify({
   echo: msg || 'Hello',
  }))
})

const port = 3000

server.listen(port, () => {
  console.log(`server listens on: ${port}`)
})

编写静态文件服务器

const http = require('http')
const fs = require('fs')
const path = require('path')
const url = require('url')

const folderPath = path.resolve(__dirname, './')

const server = http.createServer((req, res) => {
   const info = url.parse(req.url)

   const filePath = path.resolve(folderPath, './', info.path)
   
   const fileStream = fs.createReadStream(filePath)
   
   res.pipe(fileStream)
})

const port = 3000

server.listen(port, () => {
  console.log(`server listens on: ${port}`)
})

进阶

CDN - 缓存 + 加速

分布式储存、容灾

编写React SSR服务

SSR - server side rendering 服务端渲染

较 SPA,首屏渲染更快,SEO友好

较传统 HTML 模板引擎,避免重复编写代码

通常 qps 较低,编写前端代码时需考虑服务端渲染情况

const React = require('react')
const ReactDOMServer = require('react-dom/server')
const http = require('http')

function App(props) {
  return React.createElement('div', {}, props.children || 'Hello')
}

const server = http.createServer((req, res) => {
   res.end(`
     <!DOCTYPE html>
     <html>
       <head>
         <meta charset="utf-8" />
         <title>M</title>
       </head>
       <body>
         ${ReactDOMServer.renderToString(React.createElement(APP, {}, 'content'))}
       </body>
     </html>
   `)
})

const port = 3000;

server.listen(port, () => {
  console.log(`server listens on: ${port}`)
})

使用Inspector进行调试和诊断

开箱即用

使用--inspect参数启用 Inspector,之后可在/json路径下查看

查看 console 内容

breakpoint

cpuprofile 高CPU、死循环

heapsnapshot 高内存占用

性能分析

其他

Node.js 贡献入门

逐步理解 Node.js 的底层细节

支持wasm和NAPI(不同编程语言间通信)