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

60 阅读2分钟

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

应用场景

  • 前端工程化

  • Web服务端应用

    • 运行效率接近常见的编译语言
    • 社区生态丰富、工具链成熟
    • 与前端结合的场景有优势(服务端渲染 SSR)
  • Electron跨端桌面应用

    • 商业应用:vscode, slack, discord
    • 大型公司内的效率工具

运行时结构

  • V8:JavaScript Runtime,诊断调试工具(inspector)
  • libuv:eventloop(事件循环),syscall(系统调用)

特点

  1. 异步I/O

    在Node.js执行I/O操作时,会在响应返回后恢复操作,而不是阻塞线程并占用额外内存;I/O同时可以进行其他操作

  2. 单线程

    • JS单线程

      JS线程+uv线程池+V8任务线程池+V8 Inspector线程

    • 优点

      不需要考虑多线程状态同步问题,同时可以高效利用系统资源

    • 缺点

      阻塞会产生更多负面影响

  3. 跨平台

    • 大部分功能、api可以跨平台使用
    • Node.js跨平台+JS无需编译环境(+Web跨平台+诊断工具跨平台)=开发成本低(大多数场景无需考虑跨平台问题),整体学习成本低

实战

HTTP Server+Client

// server
const server2 = http.createServer((req, res) => {
    const bufs = []
    req.on('data', () => {
        bufs.push(bufs)
    })
    req.on('end', () => {
        const buf = Buffer.concat(bufs).toString('utf8')
        let msg = 'hello'
        try {
            const ret = JSON.parse(buf)
            msg = ret.msg
        } catch (err) {
        }
        const responseJson = {
            msg: `receive: ${msg}`
        }
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify(responseJson))
    })
})
// client
const req = http.request("http://127.0.0.1:3030", {
    method: 'POST', headers: {'Content-Type': 'application/json'}
}, (res) => {
    const bufs = []
    res.on('data', (buf) => bufs.push(buf))
    res.on('end', () => {
        const buf = Buffer.concat(bufs)
        const json = JSON.parse(buf)
        console.log('json.msg is:', json.msg)
    })
})

promise+async await重写

promise只适合调用一次的函数

静态服务器

const server = http.createServer(((req, res) => {
    // expected http://127.0.0.1:3000/index.html?abc=10
    const info = url.parse(req.url)
    // static/index.html
    const filePath = path.resolve(folderPath, './' + info.path)
    // stream api读取数据
    const fileStream = fs.createReadStream(filePath)
    fileStream.pipe(res)
}))

React SSR服务

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">
                     <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
                                 <meta http-equiv="X-UA-Compatible" content="ie=edge">
                     <title>Document</title>
        </head>
        <body>
          ${ReactDomServer.renderToString(React.createElement(App, {}, 'my_content'))}
        </body>
        </html>
    `)
}))

难点:

  • 打包代码
  • 思考前端代码在服务端运行时的逻辑
  • 移除对服务端无意义的副作用或重置环境

使用inspector进行调试、诊断

  • 在运行js文件时添加--inspect选项即可进入调试模式
  • http://localhost:127.0.0.1:9229/json查看详细信息;打开devtoolsFrontendUrl对应的路径可以进行调试

部署

部署工具

pm2

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