1. 事件循环与非阻塞 I/O
概述: 允许 Node.js 在单线程的情况下执行非阻塞 I/O 的机制。
组成部分:
- 调用栈: 执行同步代码。
- 回调队列: 存放在异步操作完成后等待执行的回调函数。
- 事件循环: 检查调用栈是否为空,然后从回调队列中获取回调函数。
重要函数:
process.nextTick()
: 将回调函数放入单独的队列中,在下一个事件循环周期之前运行。setImmediate()
: 将回调函数排入下一个事件循环周期中执行。- 含义: 了解这一点有助于优化应用程序性能,并避免潜在的问题。
const fs = require('fs');
fs.readFile('./file.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
console.log('正在读取文件…');
2. 缓冲区
概述: V8 堆之外的原始内存分配。
用途:
- 读取或写入文件系统。
- 处理来自网络协议的二进制数据。
- 通用的二进制数据操作。
重要方法:
- 创建:
Buffer.alloc()
,Buffer.from()
。 - 访问和修改:
buf.readUInt8()
,buf.writeUInt8()
。 - 转换:
buf.toString()
。
const buf = Buffer.from('Hello, Node.js', 'utf-8');
console.log(buf); // 输出原始缓冲区数据。
3. 流
概述: 用于流式数据的抽象。
类型:
- 可读流: 用于数据消耗(例如
fs.createReadStream()
)。 - 可写流: 用于数据生产(例如
fs.createWriteStream()
)。 - 双工流: 可读可写。
- 转换流: 在读取和写入时可以修改数据。
关键事件:
data
:当块可用时。end
:没有更多的数据可读取。error
:发生错误时。finish
:写入完成。
const fs = require('fs');
const readStream = fs.createReadStream('./largeFile.txt', 'utf8');
readStream.on('data', chunk => {
console.log(chunk);
});
4. 错误处理
- 同步代码:使用
try...catch
。 - 异步代码:
- 对于回调函数:将错误作为第一个参数传递。
- 对于 Promise:使用
.catch()
或在 async/await 中使用try...catch
。
事件监听器:
process.on('uncaughtException')
:捕获未捕获的异常。process.on('unhandledRejection')
:捕获未处理的 Promise 拒绝。
process.on('uncaughtException', (err) => {
console.error('发生了一个未捕获的错误', err);
process.exit(1); // 退出进程
});
throw new Error('这将被捕获。');
5. 集群
- 它们是什么:利用多核系统的一种方式。
- 主-工作器架构:
- 主:创建工作进程。
- 工作器:执行应用程序逻辑。
- 方法:
cluster.fork()
:生成一个新的工作器。worker.send()
:在主和工作器之间通信。
- 事件:
online
,exit
,disconnect
。
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('来自集群的问候!');
}).listen(8000);
}
6. Promises & Async/Await
- Promises:
- 状态:
pending
,fulfilled
,rejected
。 - 方法:
then()
,catch()
,finally()
。 - 创建:
new Promise((resolve, reject) => {...})
。
- 状态:
- Async/Await:
- 用法:
async function() { await someAsyncFunction(); }
。 - 错误处理:用于异步错误的
try...catch
。
- 用法:
const promiseFunc = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('2 秒后解决'), 2000);
});
};
async function asyncFunc() {
const result = await promiseFunc();
console.log(result);
}
asyncFunc();
7. Node.js 中的 ES 模块 (ESM)
- 语法:
- 导入:
import module from 'path'
。 - 导出:
export default module
。
- 导入:
- 特点:使用
import()
进行动态导入。 - 与 CommonJS 的比较:ESM 是异步的,具有静态结构,并支持树摇。
// math.js
export const add = (a, b) => a + b;
// main.js
import { add } from './math.js';
console.log(add(2, 3)); // 输出 5
8. 内存管理
- 垃圾收集:V8 的机制,用于释放未使用的内存。
- 堆快照:提供堆在特定时点的状态。
- 内存泄漏:即使不再需要,内存仍未释放的情况。
- 标识:像
node-inspect
和heapdump
这样的工具。 - 常见原因:全局变量,未移除的事件监听器。
9. 中间件模式(使用 Express.js)
- 定
义:拦截请求和响应的函数。
- 用法:
app.use(middlewareFunction)
。 - 顺序:中间件顺序很重要;它们按顺序执行。
- 内置中间件:
express.static
,express.json()
。 - 自定义中间件:
function(req, res, next) {...}
。
const express = require('express');
const app = express();
const requestTimeMiddleware = (req, res, next) => {
req.requestTime = Date.now();
next();
};
app.use(requestTimeMiddleware);
app.get('/', (req, res) => {
res.send(`请求时间:${req.requestTime}`);
});
app.listen(3000);
10. 依赖注入(DI)
- 定义:对象从外部接收它们的依赖关系的模式。
- 好处:解耦,可测试性。
- 实现:像 NestJS 这样的框架有 DI 容器。
import { Injectable, Inject } from '@nestjs/common';
@Injectable()
export class CatsService {
constructor(@Inject('DATABASE_CONNECTION') private dbConnection) {}
findAll() {
return this.dbConnection.query('SELECT * FROM cats');
}
}
11. Node.js 中的微服务
- 定义:将应用程序拆分为小型服务的架构。
- 通信:
- 同步:HTTP/REST。
- 异步:消息代理(例如 RabbitMQ)。
- 优势:可扩展性,可维护性。
12. 分析和性能优化
- 分析工具:
node --inspect
,Chrome DevTools。 - 优化:识别瓶颈,重构和测量。
- 监控:像 PM2 这样的工具用于实时监控。
node — inspect server.js
13. N-API 和原生插件
- 定义:使用 C/C++ 扩展 Node.js。
- 用途:与 C/C++ 库集成或性能关键任务时使用。
- 构建:像
node-gyp
这样的工具。
14. 使用 npm/yarn 进行包管理
- 依赖关系:在
package.json
中定义。 - 版本管理:语义化版本控制(例如
^1.0.0
)。 - 脚本:在
package.json
中的自动化脚本,如start
,test
。
15. 安全实践
- 最佳实践:
- 定期更新依赖项。
- 使用 HTTPS。
- 清理输入。
- 速率限制。
- 中间件:Helmet.js 用于安全头。
- 身份验证:OAuth,JWT。
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
app.listen(3000);