这是我参与「第四届青训营 」笔记创作活动的的第10天
01 Node.js 的应用场景 (why)
- 前端工程化
- Web服务端应用
- Electron 跨端桌面应用
02 Node.js 运行时结构 (what)
V8: JavaScript Runtime, 诊断调试工具(inspector)
libuv: eventloop(事件循环), syscall(系统调用)
举例: 用node-fetch发起请求时...
特点
-
异步IO
当Node.js执行IO操作时, 会在响应返回后恢复操作, 而不是阻塞线程并占用额外内存等待
-
单线程
指JS单线程: 实际: JS线程 + uv线程池 + V8任务线程池 + V8 Inspector线程
优点: 不用考虑多线程状态同步问题, 也就不需要锁; 同时还能比较高效地利用系统资源
缺点: 阻塞会产生更多负面影响, 解决办法: 多进程或多线程
-
跨平台
跨平台 (大部分功能, api)
Node.js跨平台 + JS 无需编译环境 ( + Web跨平台 + 诊断跨平台)
03 编写 Http Server (how)
本节目标
-
安装Node.js
推荐使用nvm管理node.js
-
编写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) }) -
编写静态文件服务器
与高性能, 可靠的服务相比, 还差什么?
- CDN: 缓存 + 加速
- 分布式存储
外部服务: cloudflare, 七牛云, 阿里云, 火山云...
-
编写React SSR服务
SSR(server side rendering) 有什么特点?
-
相比传统HTML模板引擎: 避免重复编写代码
-
相比SPA(single page application): 首屏渲染更快, SEO友好
-
缺点: 通常qps较低, 前端代码编写时需要考虑服务端渲染情况
npm i react react-dom
SSR难点
- 需要处理打包代码
- 需要思考前端代码在服务器运行时的逻辑
- 移出对服务端无意义的副作用, 或重置环境
-
-
适用inspector进行调试, 诊断
node --inspect xx.js (调试)
-
部署简介
部署要解决的问题
- 守护进程: 当进程退出时, 重新拉起
- 多进程: 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...), 同时能保留原生代码的性能
- 不同编程语言间通信的一种方案