Appearance
高级特性
事件循环 (Event Loop)
事件循环是 Node.js 实现非阻塞 I/O 的核心机制,它使得 Node.js 能够在单线程下高效处理大量并发请求 。Node.js 将耗时的 I/O 操作卸载到系统内核中,当操作完成时,内核通知 Node.js,并将相应的回调函数添加到轮询队列中等待执行 。
事件循环的阶段
Node.js 的事件循环分为几个不同的阶段,每个阶段都有一个 FIFO(先进先出)的回调队列 。
- timers: 执行由
setTimeout()和setInterval()调度的回调。 - pending callbacks: 执行被推迟到下一个循环迭代的 I/O 回调。
- idle, prepare: 仅供内部使用。
- poll: 检索新的 I/O 事件;执行与 I/O 相关的回调。在适当的时候,Node.js 会在此阶段阻塞。
- check: 执行
setImmediate()的回调。 - close callbacks: 执行关闭事件的回调,例如
socket.on('close', ...)。
这个模型确保了 JavaScript 在处理 I/O 时不会被阻塞,从而能够高效地处理其他任务 。
Stream (流)
Stream 是 Node.js 中处理流式数据的抽象接口。它允许你以小块(chunk)的方式读取或写入数据,而不是一次性将所有数据加载到内存中。这使得处理大数据集或实时数据流变得非常高效。
Stream 的类型
Node.js 中有四种基本的流类型:
- Readable: 可读流,用于读取数据,例如
fs.createReadStream()。 - Writable: 可写流,用于写入数据,例如
fs.createWriteStream()。 - Duplex: 双工流,既可读又可写,例如
net.Socket。 - Transform: 转换流,是一种特殊的双工流,可以在读写过程中修改或转换数据,例如
zlib.createGzip()。
使用 Stream 的优势
- 内存效率: 无需将大量数据加载到内存中,从而减少内存消耗。
- 时间效率: 在数据完全加载之前就可以开始处理,从而缩短处理时间。
示例:管道 (Pipe)
pipe 方法是处理流的强大工具,它可以将一个可读流的输出连接到一个可写流的输入。这在处理文件时非常有用。
javascript
const fs = require('fs');
const zlib = require('zlib');
// 创建一个可读流来读取文件
const readableStream = fs.createReadStream('input.txt');
// 创建一个可写流来写入压缩文件
const writableStream = fs.createWriteStream('output.txt.gz');
// 创建一个 Gzip 转换流
const gzip = zlib.createGzip();
// 使用 pipe 将读取、压缩和写入操作连接起来
readableStream.pipe(gzip).pipe(writableStream);
console.log('文件压缩完成。');这个例子展示了如何使用 pipe 将文件读取、Gzip 压缩和文件写入这三个步骤串联起来,形成一个高效的数据处理管道。