这是我参与「第五届青训营」笔记创作活动的第7天。
应用场景
-
前端工程化
-
Web服务端应用
- 运行效率接近常见的编译语言
- 社区生态丰富、工具链成熟
- 与前端结合的场景有优势(服务端渲染 SSR)
-
Electron跨端桌面应用
- 商业应用:vscode, slack, discord
- 大型公司内的效率工具
运行时结构
- V8:JavaScript Runtime,诊断调试工具(inspector)
- libuv:eventloop(事件循环),syscall(系统调用)
特点
-
异步I/O
在Node.js执行I/O操作时,会在响应返回后恢复操作,而不是阻塞线程并占用额外内存;I/O同时可以进行其他操作
-
单线程
-
JS单线程
JS线程+uv线程池+V8任务线程池+V8 Inspector线程
-
优点
不需要考虑多线程状态同步问题,同时可以高效利用系统资源
-
缺点
阻塞会产生更多负面影响
-
-
跨平台
- 大部分功能、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便捷地利用多进程
- 记录进程状态,用于诊断