这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
1. 应用场景
1. 前端工程化
- Bundle:webpack、vite、esbuild、parcel
- Uglify:Uglifyjs
- Transpile: babel, ts
- 其他语言加入竞争
- 现状:难以替代
2. Web 服务端应用
- 学习曲线平缓,开发效率较高
- 效率接近常见的编译语言
- 社区生态丰富、工具链成熟(npm,V8 inspector)
- 与前端结合的场景有优势(SSR)
- 现状:竞争激烈,Node.js有自己独特的优势
3. Electron跨端桌面应用
- 商业应用:vscode、discord、zoom
- 大型公司内部效率工具
- 现状:大部分场景在选型时都值得考虑
Node.js在字节
- BFF,接口的需求者参与实现接口的编写
- 服务端应用:头条搜索、西瓜视频、懂车帝——前端开发者来参与实现nodejs
- Electron:飞书、飞连
- 每年新增1000+应用
2. 运行时结构
Node.js
1. 应用场景
1. 前端工程化
- Bundle:webpack、vite、esbuild、parcel
- Uglify:Uglifyjs
- Transpile: babel, ts
- 其他语言加入竞争
- 现状:难以替代
2. Web 服务端应用
- 学习曲线平缓,开发效率较高
- 效率接近常见的编译语言
- 社区生态丰富、工具链成熟(npm,V8 inspector)
- 与前端结合的场景有优势(SSR)
- 现状:竞争激烈,Node.js有自己独特的优势
3. Electron跨端桌面应用
- 商业应用:vscode、discord、zoom
- 大型公司内部效率工具
- 现状:大部分场景在选型时都值得考虑
Node.js在字节
- BFF,接口的需求者参与实现接口的编写
- 服务端应用:头条搜索、西瓜视频、懂车帝——前端开发者来参与实现nodejs
- Electron:飞书、飞连
- 每年新增1000+应用
2. 运行时结构
- V8:JavaScript Runtime,诊断挑食工具
- libuv:eventloop,syscall
- 举例:node-fetch发起请求时
- 用户代码→V8引擎执行代码→Node.js Core(JS) → Node.js Core(C++)→llhttp进行报文序列化和反序列化→libuv建立tcp连接→llhttp→Core→用户代码
特点
1. 异步
不会阻塞线程,效率高,内存占用少
2. 单线程
实际:JS线程+uv线程池(默认4个,执行加密解密等消耗大的操作)+V8线程池+V8 Inspector线程(程序死循环崩溃仍能调试)
- 优点:不用考虑多线程状态同步问题,也就不需要锁;同时还能比较高地利用系统资源
- 去欸但:阻塞会产生更多负面影响
- 解决办法:多进程或多线程
3. 跨平台
- 跨平台(大部分功能、api)
- Node.js跨平台+JS无需编译环境(+Web跨平台+诊断工具跨平台)
- =开发成本低,学习成本低
3. 编写HTTP Server
0. Installation
- 推荐nvm,便于版本管理
1. 编写http server & client收发Get、Post请求
- server.js
const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
res.end('hello');
})
server.listen(port, () => {
console.log('listening on: ', port);
})
- http_server_json.js
const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
const bufs = [];
req.on('data', (buf) => {
bufs.push(buf);
})
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));
})
})
server.listen(port, () => {
console.log('listening on: ', port);
})
- http_client.js
const http = require('http')
const body = JSON.stringify({
msg: 'Hello from client',
});
const req = http.request('http://127.0.0.1:8000', {
method: 'POST',
header: {
'Content-Type': 'application/json',
}
},(res) => {
const bufs = []
res.on('data', (buf) => {
bufs.push(buf);
})
res.on('end', () => {
const buf = JSON.parse(Buffer.concat(bufs));
console.log('json.msg is:', buf.msg);
})
})
req.end(body);
- Promisify: 将callback转换为promise,增加代码可读性
2. 编写静态文件服务器
- filestream,减少内存占用
- 还需要什么:
- CDN:缓存+加速
- 分布式储存,容灾
- 外部服务:cloudflare,阿里云
3. 编写React SSR服务
- 特点
- 相比传统HTML模板引起:避免重复编写代码
- 相比SPA:首屏渲染更快,SEO友好
- 缺点:
- 通常qps较低,编写时需要考虑服务端渲染情况
- 难点:
-
需要处理打包代码
-
需要思考前端代码在服务端运行时的逻辑
async compnentDidMount() {}
-
移除对服务端无意义的副作用,或重置环境
-
4. 适用inspector进行调试、诊断
- node —inspect
- open http://localhost:9229/json
- 命令面板可以打开源代码文件,进行断点调试
- Heap Snapshot,诊断内存泄漏
- CPU Profiles,诊断CPU占用
5. 部署简介
- 守护进程:当进程退出时,重新拉起
- 多进程:cluster便捷地利用多进程
- 记录进程状态,用于诊断
- 容器环境
- 通常有健康检查的手段,秩序考虑多核CPU利用率即可
延伸话题
贡献代码
- 好处:
- 理解底层细节
- 自我证明
- 解决社区问题
- 难点
- 花时间
编译Node.js
WASM,NAPI
- Node.js是执行WASM的天然容器
- NAPI执行C接口的代码,同时能保留原生代码的性能
- 不同编程语言间通信的一种方案
- V8:JavaScript Runtime,诊断挑食工具
- libuv:eventloop,syscall
- 举例:node-fetch发起请求时
- 用户代码→V8引擎执行代码→Node.js Core(JS) → Node.js Core(C++)→llhttp进行报文序列化和反序列化→libuv建立tcp连接→llhttp→Core→用户代码
特点
1. 异步
不会阻塞线程,效率高,内存占用少
2. 单线程
实际:JS线程+uv线程池(默认4个,执行加密解密等消耗大的操作)+V8线程池+V8 Inspector线程(程序死循环崩溃仍能调试)
- 优点:不用考虑多线程状态同步问题,也就不需要锁;同时还能比较高地利用系统资源
- 去欸但:阻塞会产生更多负面影响
- 解决办法:多进程或多线程
3. 跨平台
- 跨平台(大部分功能、api)
- Node.js跨平台+JS无需编译环境(+Web跨平台+诊断工具跨平台)
- =开发成本低,学习成本低
3. 编写HTTP Server
0. Installation
- 推荐nvm,便于版本管理
1. 编写http server & client收发Get、Post请求
- server.js
const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
res.end('hello');
})
server.listen(port, () => {
console.log('listening on: ', port);
})
- http_server_json.js
const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
const bufs = [];
req.on('data', (buf) => {
bufs.push(buf);
})
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));
})
})
server.listen(port, () => {
console.log('listening on: ', port);
})
- http_client.js
const http = require('http')
const body = JSON.stringify({
msg: 'Hello from client',
});
const req = http.request('http://127.0.0.1:8000', {
method: 'POST',
header: {
'Content-Type': 'application/json',
}
},(res) => {
const bufs = []
res.on('data', (buf) => {
bufs.push(buf);
})
res.on('end', () => {
const buf = JSON.parse(Buffer.concat(bufs));
console.log('json.msg is:', buf.msg);
})
})
req.end(body);
- Promisify: 将callback转换为promise,增加代码可读性
2. 编写静态文件服务器
- filestream,减少内存占用
- 还需要什么:
- CDN:缓存+加速
- 分布式储存,容灾
- 外部服务:cloudflare,阿里云
3. 编写React SSR服务
- 特点
- 相比传统HTML模板引起:避免重复编写代码
- 相比SPA:首屏渲染更快,SEO友好
- 缺点:
- 通常qps较低,编写时需要考虑服务端渲染情况
- 难点:
-
需要处理打包代码
-
需要思考前端代码在服务端运行时的逻辑
async compnentDidMount() {}
-
移除对服务端无意义的副作用,或重置环境
-
4. 适用inspector进行调试、诊断
- node —inspect
- open http://localhost:9229/json
- 命令面板可以打开源代码文件,进行断点调试
- Heap Snapshot,诊断内存泄漏
- CPU Profiles,诊断CPU占用
5. 部署简介
- 守护进程:当进程退出时,重新拉起
- 多进程:cluster便捷地利用多进程
- 记录进程状态,用于诊断
- 容器环境
- 通常有健康检查的手段,秩序考虑多核CPU利用率即可
延伸话题
贡献代码
- 好处:
- 理解底层细节
- 自我证明
- 解决社区问题
- 难点
- 花时间
编译Node.js
WASM,NAPI
- Node.js是执行WASM的天然容器
- NAPI执行C接口的代码,同时能保留原生代码的性能
- 不同编程语言间通信的一种方案