理解Node.js的流

目录
  1. 1. 流的产生
  2. 2. Readable Stream
  3. 3. Writable Stream
  4. 4. Duplex Stream
  5. 5. Transform Stream
  6. 6. 参考

流的产生

如下,读取一个文件,把file.js全部读取到内存,当file.js文件很小的时候并没有什么问题

1
2
3
4
const fs = require('fs');

fs.readFile('./file.js', (err, data) => {
});

但是当file.js有几G、几十G或更大的时候,把整个文件读取到内存显然就会出现内存不够用的问题。

可不可以每次读取固定长度的数据到缓冲区,处理完缓冲区后再继续读取?这就是流。

Node.js的Stream模块提供了四种类型的流:

  • Readable Streams (可读流)
  • Writable Streams (可写流)
  • Duplex Streams (双工流)
  • Transform Streams (转换流)

Readable Stream

可读流处于2种模式之一:Flowing ModePaused Mode

绑定 data 会自动触发Flowing Mode,第一次 data 事件会在下一个 tick 中触发。

从系统底层读取数据并push()到缓存池,达到highWaterMark后 push() 返回 false,资源停止流向缓存池,并触发data事件消费数据。

切换到Flowing模式的方法:

  • 监听data事件
  • 调用stream.resume()方法
  • 调用stream.pipe()方法将数据发送到 Writable

Stream 默认是Paused模式,必须显式调用stream.read()方法来从流中读取数据。每一次数据达到缓存池都会触发一次 readable 事件,也就是每一次 push() 都会触发 readable。

切换到Paused模式的方法:

  • 监听readable事件
  • 如果不存在管道目标(pipe destination),调用 stream.pause()
  • 如果存在管道目标,取消 data 事件监听,并调用 stream.unpipe() 方法移除所有管道

Writable Stream

write() 的数据会进入队列池,如果达到highWaterMark,则会返回 false,否则返回 true,返回 false 后仍然可以继续 write(),数据会缓存在内存中不会丢失,write() 会继续返回 false。

write() 返回 false 后, 最好等drain事件触发后再继续写入。

Duplex Stream

Duplex 是同时实现了 Readable 和 Writable,但输出与输入没有关系。

Transform Stream

Tranform 继承自 Duplex,但在 Transform 中 Writable 写入的数据经变换后会自动添加到 Readable。

参考

  1. 深入理解 Node Stream 内部机制
  2. Node.js Stream - 基础篇
  3. Node.js Stream - 进阶篇
  4. Node.js Stream - 实战篇