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

46 阅读2分钟

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

一、本堂课重点内容:

  1. 介绍 Node.js 的应用场景
  2. 介绍 Node.js 运行时结构
  3. 如何用编写 Http Server
  4. 延伸话题

二、详细知识点介绍:

Node.js应用场景

  1. 前端工程化

  2. web服务端应用

    学习曲线平缓,开发效率高,运行效率高,社区生态丰富工具链成熟(npm,V8 inspector),与前端结合的场景有优势(SSR)

  3. Electron跨段桌面应用

    商业应用:vscode,slack,zoom

    大型公司内的效率工具

Node.js运行时结构

  1. V8:JavaScript Runtime,诊断调试工具

  2. libuv:eventloop事件循环,syscall系统调用

  3. 特点

  • 异步IO

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

  • 单线程

    不适合做CPU密集的操作;worke_thread可以起独立线程

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

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

    缺点:阻塞会产生更多负面影响

    解决:多进程或多线程

  • 跨平台

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

    开发成本低,学习成本低

三、实践练习例子:

用node-fetch发起请求的过程:

  1. 使用npm安装node-fetch模块

  2. 在用户代码里调用node-fetch模块

  3. 调用Node.js Core(JavaScript)→Node.js Core(C++)

  4. 调用llhttp做HTTP协议的序列化和反序列化

  5. 得到的数据通过llibuv创建HTTP连接发向远端

  6. 反之亦然

编写HTTP server

  1. hello world
const http = require('http')

const server = http.createServer((req, res) =>{
    res.end('hello')
})

const port = 3000

server.listen(port, () => {
    console.log('listening on:', port);
})
  1. JSON
const http = require('http')

const server = http.createServer((req, res) =>{
    const bufs = []
    req.on('data', (buf) => {
        bufs.push(buf)
    })
    req.on('end', () => {
        const buf = Buffer.concat(bufs).toString('utf-8')
        let msg = 'Helo'
        try{
            const ret = JSON.parse(buf)
            msg = ret.msg
           
        }catch (err){
            
        }
        const responseJosn = {
            msg: 'receive: ${msg}'
        }
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify(responseJosn))
    })
})

const port = 3000

server.listen(port, () => {
    console.log('listening on:', port);
})
  1. Client
const http = require('http')

const body = JSON.stringify({
    msg: 'Hello from my own client',
})

const req = http.request('<http://127.0.0.1:3000>', {
    method: 'POST',
    headers: {
        'Content-Type':'application/json',

    }
}, (res =>{
    const bufs = []
    res.on('data', () => {
        const buf = Buffer.concat(bufs)
        const json  =JSON.parse(buf)
        console.log('json.msg is:', json.msg);
    })
}))

req.end(body)
  1. 用Promise+async await重写这两个例子

    将callback转换成promise

function wait(t){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
        },t)
    })
}

wait(1000).then(() => {console.log('get called')})
  1. 编写简单的静态文件服务
const http = require('http')
const fs = require('fs')
const path = require('path')
const url = require('url')

const port = 3000
const server = http.createServer((req, res) =>{
    const info = url.parse(req.url)
    const file = fs.createReadStream(path.resolve(__dirname, '.' + info.pathname))
})

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

与高性能、可靠的服务相比,还差:

CDN:缓存+加速

分布式储存,容灾

  1. React SSR
  • 特点

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

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

  • 缺点

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

  • 难点

    处理打包代码

    思考前端代码在服务器运行时的逻辑

    移除对服务器端无意义的副作用,或重置环境

  1. 部署
  • 要解决的问题

    守护进程:当进程退出时,重新拉起

    多进程:cluster便携地利用多进程

    记录进程状态,用于诊断

  • 容器环境

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