Node.js笔记
参加字节跳动的青训营时写的笔记。这部分是欧阳亚东老师讲的课。
个人博客(欢迎光临):Node.js笔记
1. 应用场景
- 前端工程化
- Web服务端应用
- 运行效率接近常见的编译语言
- 社区生态丰富、工具链成熟(npm,V8 inspector)
- 与前端结合的场景有优势(服务端渲染 SSR)
- Electron跨端桌面应用
- 商业应用:vscode, slack, discord
- 大型公司内的效率工具
2. 运行时结构
- V8:JavaScript Runtime,诊断调试工具(inspector)
- libuv:eventloop(事件循环),syscall(系统调用)
2.1 特点
-
异步I/O:当Node.js执行I/O操作时,会在响应返回后恢复操作,而不需要阻塞线程(占用额外线程)。
-
单线程:
-
JS单线程
- 实际:JS线程+uv线程池+V8任务线程池+V8 inspector 线程
-
worker_thread可以单独起独立线程,每一个线程的模型没有太大变化
-
优点:不需要考虑多线程状态同步问题(不需要锁),能够高效地利用系统资源
-
缺点:阻塞会产生更多的负面影响, 解决方法:多进程或多线程
-
-
跨平台(大部分功能, api):开发成本低(大部分情景不需要考虑跨平台问题),学习成本低
- Node.js 跨平台 + JavaScript无需编译环境 + Web跨平台 + 诊断工具跨平台
3. 编写Http Server
3.1 Hello
const http = require("http");
const port = 8081;
const server = http.createServer((req, res) => {
res.end("Hello");
});
server.listen(port, () => {
console.log(`Listen at ${port}`);
})

3.2 JSON数据
用户把JSON数据POST给服务器,服务器再把数据中的msg取出来,返回给用户
服务器端:
const http = require("http");
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); // 转换成JSON对象
msg = ret.msg;
} catch (err) {
// 如果抛出异常的话,则msg是初始值Hello,无需处理异常
}
const responseJson = {
msg: `receive: ${msg}`
};
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(responseJson)); // JSON对象转换为字符串
})
});
const port = 8081;
server.listen(port, () => {
console.log(`Listen at ${port}`);
})
客户端:
const http = require('http');
const body = JSON.stringify({
msg: 'Hello from client'
});
const req = http.request('http:/127.0.0.1:8081', {
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);
先打开服务器端,再打开客户端。(第一个文件为json.js,第二个为client.js。则先执行node json.js,再执行node client.js)
收到返回信息:

3.3 用Promise + async await 重写3.2
技巧:将callback转换成promise
不是所有的回调函数都适合转换成promise,而是只调用一次的回调函数才适合转换为promise。即createServer()不适合转换为promise。
json.js修改后(输出结果一样)
const http = require("http");
const server = http.createServer(async (req, res) => {
// 从客户端接收数据
const msg = await new Promise((resolve, reject) => {
const bufs = [];
req.on('error', (err) => {
reject(err)
})
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); // 转换成JSON对象
msg = ret.msg;
} catch (err) {
// console.log(err);
}
resolve(msg); // 返回msg
})
})
// 响应
const responseJson = {
msg: `receive: ${msg}`
};
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(responseJson));
});
const port = 8081;
server.listen(port, () => {
console.log(`Listen at ${port}`);
})
3.4 静态文件服务
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<p>Hello</p>
<script>
alert("Hello")
</script>
</body>
</html>
static_server.js
const http = require("http");
const fs = require('fs');
const path = require('path');
const url = require('url');
const folderPath = path.join(__dirname, 'static');
const server = http.createServer((req, res) => {
const info = url.parse(req.url);
const filePath = path.join(folderPath, info.path);
const filestream = fs.createReadStream(filePath);
// createReadStream好处: 减少占用内存空间
filestream.pipe(res);
});
const port = 8081;
server.listen(port, () => {
console.log(`Listen at ${port}`);
})

执行node static_server.js 后,打开http://localhost:8081/index.html

之后会报点小错,因为没有ico图标(忽视就好)
3.5 React SSR
SSR(server side rendering):服务端渲染
- 相对于传统HTML模板引擎:可以避免重复编写代码
- 相比于SPA:首屏渲染更快,SEO友好(SPA应用需要加载完所有的js代码后,才可以给用户返回数据)
首先要先安装react相关的包,npm i react react-dom
下面就是通过React SSR实现显示Hello的代码(有一点不太明白,还是得等会用ReactDOM、ReactDOMServer模块)
ssr.
const React = require('react');
const ReactDOMServer = require('react-dom/server')
const http = require("http");
function App(props) {
return React.createElement('div', {}, props.children || 'Hello');
}
const port = 8081;
const server = http.createServer((req, res) => {
res.end(`
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
</head>
<body>
${ReactDOMServer.renderToString(
React.createElement(App, {}, 'Hello'))}
</body>
</html>
`);
});
server.listen(port, () => {
console.log(`Listen at ${port}`);
})
3.6 Debug
V8 Inspector:开箱即用、与前端开发已知、跨平台
场景:
- 查看console.log内容
- breakpoint
- 性能分析
使用:
-
node --inspect ssr.js -
打开http://127.0.0.1:9229/json
-
复制打开下图红框内容

-
进入下图界面

控制台显示连接上

-
对于阻塞的情况,可以使用log point,相当于console.log

3683

被折叠的 条评论
为什么被折叠?



