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

26 阅读2分钟

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

在上这课之前,我有接触过node.js,但更多的是一些小的应用,没有深入去了解过node.js,学了这节课,让我对于node.js的底层有了更深的了解。

Node.js的应用场景

Node.js的应用场景

  • 前端工程化
  • Web服务端应用
  • Electron跨端桌面应用

前端工程化

  • Bundle:webpack,vite,esbuild,parcel
  • Uglify:uglifyhs
  • Transpile:bablejs,typescript
  • 其他语言加入竞争:esbuild,parcel,prisma
  • 现状:难以替代

Web服务端应用

  • 学习曲线平缓,开发效率较高
  • 运行效率接近常用的编译语言
  • 社区生态丰富及工具链成熟(npm,V8 inspector)
  • 与前端结合的场景会有优势(SSR)
  • 现状:竞争激烈,Node.js有自己独特的优势

Electron跨端桌面应用

  • 商业应用:vscode,slack,discord,zoom
  • 大型公司内的效率工具
  • 现状:大部分场景在选型时,都值得考虑

Node.js运行时结构

image.png

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

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

特点

  • 异步I/O
  • 单线程
    • 实际:JS线程+uv线程池+V8任务线程池+V8 Inspector线程
  • 跨平台(大部分功能,api)
    • Node.js跨平台+JS无需编译环境(+Web跨平台+诊断攻击跨平台)

编写Http Server

Http Server + Http Client

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', () => {
    const buf = Buffer.concat(bufs).toString('utf-8')
    let msg = 'hello'
    try {
      const ret = JSON.parse(buf)
      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)
})

Http 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', (buf) => {
    bufs.push(buf)
  })
  res.on('end', () => {
    const buf = Buffer.concat(bufs)
    const json = JSON.parse(buf)

    console.log('json.msg is', json.msg)
  })
})
req.end(body)

Promise+async await重写

const { rejects } = require('assert')
const http = require('http')
const { resolve } = require('path')
const port = 3000
const server = http.createServer(async (req, res) => {
  //receive body from client
  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', () => {
      const buf = Buffer.concat(bufs).toString('utf-8')
      let msg = 'hello'
      try {
        const ret = JSON.parse(buf)
        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)
})

React SSR

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

function App () {
  return React.createElement('h1', {
    children: 'Hello',
  })
}

const port = 3000

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html')
  res.end(
    `
    <DOCTYPE html>
    <html>
      <head>
      <title>My App</title>
      </head>
      <body>
        <div id="main">
          ${ReactDOMServer.renderToString(React.createElement(App))}
        </div>
      </body>
    </html>
    `
  )
})

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

延伸

Node.js贡献代码

好处

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

难点

  • 花时间

诊断/追踪

  • 诊断是一个低频、重要同时也相当有挑战的方向。是企业衡量自己能否依赖一门语言的重要参考。
  • 难点
    • 需要了解Node.js底层,需要了解操作系统以及各种工具
    • 需要经验