本文档提供了 Node.js 中流 API 的全面概述,它是处理流数据的基本抽象。通过一次处理一小块数据而不是将所有数据加载到内存中,流可以实现高效的数据处理。它们特别适用于处理大文件、网络通信和其他 I/O 操作。
有关经常使用流的文件系统 API 的信息,请参阅 文件系统。
流是 Node.js 中用于处理流数据的抽象接口。它们提供了一种以内存高效的方式读取或写入连续数据流的方法。所有流都是 EventEmitter 类的实例,允许它们发出事件并响应事件。
Node.js 中的四种基本流类型是
来源:lib/stream.js54-108 doc/api/stream.md35-46
Readable 和 Writable 流都会在内部缓冲数据。潜在的缓冲数据量取决于创建流时传递的 highWaterMark 选项。对于普通流,highWaterMark 指定总字节数。对于对象模式的流,它指定对象总数。
当 Readable 流的内部缓冲区达到 highWaterMark 指定的阈值时,它将暂时停止从底层资源读取,直到缓冲数据被消耗。同样,当 Writable 流的内部缓冲区超过 highWaterMark 时,对 write() 的调用将返回 false,表明生产者应停止发送数据,直到发出 'drain' 事件。
Readable 流是可从中消耗数据的源的抽象。例如,从文件读取、从 HTTP 响应读取或从 TCP 套接字读取。
有多种方法可以创建 Readable 流
从现有数据源实例化
通过扩展 Readable 类来实现自定义 Readable 流
Readable 流可以通过几种方式进行消耗
使用事件监听器
使用 pipe() 方法将数据发送到 Writable 流
使用异步迭代(配合 for await...of)
使用流运算符(Node.js 16.x 及更高版本)
来源:doc/api/stream.md441-467 doc/api/stream.md195-246
Writable 流是可向其中写入数据的目标(destination)的抽象。例如,写入文件、写入 HTTP 请求或写入 TCP 套接字。
要实现自定义 Writable 流,请扩展 Writable 类并实现 _write() 方法
可以使用 write() 和 end() 方法将数据写入 Writable 流
write() 方法返回一个布尔值,指示是否可以继续写入,或者内部缓冲区是否已满。如果返回 false,则应等待 'drain' 事件发出后再写入更多数据,以避免使流过载
来源:doc/api/stream.md468-499 doc/api/stream.md537-562
Duplex 流是实现 Readable 和 Writable 接口的流。Transform 流是 Duplex 流的一种特殊类型,其输出由输入计算得出。
Duplex 流的例子包括 TCP 套接字、zlib 流和 crypto 流。Duplex 流为读写维护单独的内部缓冲区,允许每侧独立操作。
Transform 流是 Duplex 流,其输出是根据输入计算得出的。它们同时实现 Readable 和 Writable 接口,并在将数据提供读取之前转换写入的数据。
Transform 流的例子包括 zlib 压缩流和 crypto 密码流。
要实现自定义 Transform 流,请扩展 Transform 类并实现 _transform() 方法
Node.js 提供了一组流运算符,用于以更函数式的方式处理流。从 Node.js v16 开始,这些运算符可在 Readable 流上使用。
使用示例
来源:lib/internal/streams/operators.js68-216 lib/internal/streams/operators.js256-268 test/parallel/test-stream-map.js30-57 test/parallel/test-stream-filter.js12-48 test/parallel/test-stream-toArray.js9-38
Node.js 提供了几个用于处理流的实用函数
pipeline 函数将流连接起来,并正确处理错误和清理
还有一个基于 Promise 的版本可从 'node:stream/promises' 获得
finished 函数等待流完成或出错
还有一个基于 Promise 的版本
来源:doc/api/stream.md65-246 doc/api/stream.md250-321
默认情况下,流在 Buffer、字符串、TypedArrays 或 DataViews 上操作。当使用 objectMode: true 选项创建流时,它将在 JavaScript 对象上操作。
二进制模式和对象模式之间的主要区别
highWaterMark 选项指定总字节数,而在对象模式下,它指定对象总数。null(表示流结束)以外的任何 JavaScript 值。背压是流数据处理中的一个重要概念。它指的是一种机制,允许较慢的消费者向较快的生产者发出信号,表明其需要减速以避免使消费者过载。
在 Node.js 流中,背压是自动处理的
highWaterMark 时,流会暂时停止从底层资源读取。highWaterMark 时,write() 方法将返回 false。然后生产者应停止发送数据,直到发出 'drain' 事件。处理背压的示例
来源: doc/api/stream.md367-381 doc/api/stream.md532-562
许多 Node.js API 使用或返回流
fs.createReadStream(), fs.createWriteStream()stdout, stdin, 和 stderr 流组合不同流类型的示例
来源: doc/api/stream.md473-486 doc/api/crypto.md326-395 doc/api/tls.md572-582
处理错误是使用流时一个重要的方面。有几种处理流中错误的方法
基于事件的错误处理:监听流上的 'error' 事件。
使用 pipeline():pipeline() 函数会自动处理错误和清理。
使用 finished():finished() 函数检测流何时完成或出错。
将 async/await 与 Promise 结合使用:使用 pipeline() 和 finished() 的基于 Promise 的版本。
来源: doc/api/stream.md65-113 doc/api/stream.md250-321
在使用 Node.js 流时,请考虑以下最佳实践
write() 的返回值,并在需要时等待 'drain' 事件。end(),并处理 Readable 流上的 'end' 事件。map()、filter() 等运算符。for await...of,您可以更清晰地消费 Readable 流。来源: doc/api/stream.md323-396 lib/internal/streams/operators.js68-216
Node.js 的 Streams API 为处理流动数据提供了一个强大的抽象。它通过以小块处理数据、管理反压以及跨不同类型 I/O 操作提供一致的接口,实现了高效的数据处理。理解流对于构建高性能的 Node.js 应用程序至关重要,尤其是那些处理大量数据或网络通信的应用程序。
通过利用 Node.js 提供的流运算符和实用函数,您可以构建复杂的、具有干净、可维护代码的数据处理管道。
刷新此 Wiki
最后索引时间2025年4月17日(e61937)