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

63 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第10天

PPT: bytedance.feishu.cn/file/boxcnV…

01 Node.js 的应用场景 (why)

  1. 前端工程化
  2. Web服务端应用
  3. Electron 跨端桌面应用

02 Node.js 运行时结构 (what)

V8: JavaScript Runtime, 诊断调试工具(inspector)

libuv: eventloop(事件循环), syscall(系统调用)

举例: 用node-fetch发起请求时...

特点

  1. 异步IO

    当Node.js执行IO操作时, 会在响应返回后恢复操作, 而不是阻塞线程并占用额外内存等待

  2. 单线程

    指JS单线程: 实际: JS线程 + uv线程池 + V8任务线程池 + V8 Inspector线程

    优点: 不用考虑多线程状态同步问题, 也就不需要锁; 同时还能比较高效地利用系统资源

    缺点: 阻塞会产生更多负面影响, 解决办法: 多进程或多线程

  3. 跨平台

    跨平台 (大部分功能, api)

    Node.js跨平台 + JS 无需编译环境 ( + Web跨平台 + 诊断跨平台)

03 编写 Http Server (how)

本节目标

  1. 安装Node.js

    推荐使用nvm管理node.js

  2. 编写Http Server + Client, 收发GET, POST请求

     // Server
     const http = require('http')
     ​
     const port = 10000
     ​
     const server = http.createServer((req, res) => {
         const bufs = []
         req.on('data', (buf) => {
             bufs.push(buf) // 把body上的数据储存到bufs
         })
         req.on('end', () => {
             const buf = Buffer.concat(bufs).toString('utf8') // 传输完成后, 拼接, 并转成utf8
             let msg = 'Hello'
             try {
                 const ret = JSON.parse(buf) // 尝试解析成json
     ​
                 const msg = ret.msg
     ​
             } catch (err) {
                 // res.end('invalid json')
             }
     ​
             const responseJson = {
                 msg: `receive: ${msg}`
             }
             
             res.setHeader('Content-Type', 'application/json')
             res.end(JSON.stringify(responseJson)) // 序列化 并返回
         })
     })
     ​
     server.listen(port, () => {
         console.log('listening on: ', port)
     })
    
     // Client
     const http = require('http')
     ​
     const body = JSON.stringify({
         msg: 'Hello from My own client',
     })
     ​
     const req = http.request('http://127.0.0.1:10000', {
         method: 'POST',
         headers: {
             'Content-Type': {
                 'Content-Type': 'application/json'
             }
         }
     }, res => {
         const bufs = []
         res.on('data', buf => {
             bufs.push(buf)
         })
         res.on('end', () => {
             const buf = Buffer.concat(bufs).toString('utf-8')
             const json = JSON.parse(buf)
     ​
             console.log('json.msg is: ', json.msg)
         })
     })
     ​
     req.end(body)
    

    将callback转换成promise (Promisify)

     const http = require('http')
     ​
     const port = 10000
     ​
     const server = http.createServer(async (req, res) => {
         // recevie body from client
         const msg = await new Promise((resolve, reject) => {
             const bufs = []
             req.on('data', (buf) => {
                 bufs.push(buf) // 把body上的数据储存到bufs
             })
             req.on('error', err => {
                 reject(err)
             })
             req.on('end', () => {
                 const buf = Buffer.concat(bufs).toString('utf8') // 传输完成后, 拼接, 并转成utf8
                 let msg = 'Hello'
                 try {
                     const ret = JSON.parse(buf) // 尝试解析成json
         
                     const msg = ret.msg
         
                 } catch (err) {
                     // res.end('invalid json')
                 }
                 resolve(msg)
             })
         })
     ​
     ​
     ​
         // response
     ​
         
         const responseJson = {
             msg: `receive: ${msg}`
         }
         
         res.setHeader('Content-Type', 'application/json')
         res.end(JSON.stringify(responseJson)) // 序列化 并返回
     })
     ​
     server.listen(port, () => {
         console.log('listening on: ', port)
     })
    
  3. 编写静态文件服务器

    与高性能, 可靠的服务相比, 还差什么?

    1. CDN: 缓存 + 加速
    2. 分布式存储

    外部服务: cloudflare, 七牛云, 阿里云, 火山云...

  4. 编写React SSR服务

    SSR(server side rendering) 有什么特点?

    • 相比传统HTML模板引擎: 避免重复编写代码

    • 相比SPA(single page application): 首屏渲染更快, SEO友好

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

    npm i react react-dom

    SSR难点

    1. 需要处理打包代码
    2. 需要思考前端代码在服务器运行时的逻辑
    3. 移出对服务端无意义的副作用, 或重置环境
  5. 适用inspector进行调试, 诊断

    node --inspect xx.js (调试)

  6. 部署简介

    部署要解决的问题

    • 守护进程: 当进程退出时, 重新拉起
    • 多进程: cluster 便捷地利用多进程
    • 记录进程状态, 用于诊断

    容器环境

    • 通常有健康检查的手段, 只需考虑多核cpu利用率即可

04 延申话题

快速了解Node.js代码

  • Node.js Core贡献入门

好处

  • 从使用者的角色逐步理解底层细节, 可以解决更复杂的问题
  • 自我证明, 有助于职业发展
  • 解决社区问题, 促进社区发展

缺点

  • 花时间

诊断/追踪

  • 诊断是一个低频, 重要同时也相当有挑战的方向. 是企业衡量自己能否依赖一门语言的重要参考

  • 技术咨询行业中的热门角色

  • 难点

    • 需要了解Node.js底层, 需要了解操作系统以及各种工具
    • 需要经验

WASM, NAPI

  • Node.js(因为V8) 是执行WASM(WebAssembly)代码的天然容器, 和浏览器WASM是同一运行时, 同时Node.js支持WASM
  • NAPI执行C接口的代码(C/C++/Rust...), 同时能保留原生代码的性能
  • 不同编程语言间通信的一种方案