浅谈Node.js:理解stream

2020-06-17 07:07:32易采站长站整理

Stream在node.js中是一个抽象的接口,基于EventEmitter,也是一种Buffer的高级封装,用来处理流数据。流模块便是提供各种API让我们可以很简单的使用Stream。

流分为四种类型,如下所示:

Readable,可读流
Writable,可写流
Duplex,读写流
Transform,扩展的Duplex,可修改写入的数据

1、Readable可读流

通过stream.Readable可创建一个可读流,它有两种模式:暂停和流动。

在流动模式下,将自动从下游系统读取数据并使用data事件输出;暂停模式下,必须显示调用

stream.read()
方法读取数据,并触发data事件。

所有的可读流最开始都是暂停模式,可以通过以下方法切换到流动模式:

监听’data’事件
调用

stream.resume()
方法
调用
stream.pipe()
方法将数据输出到一个可写流Writable

同样地,也可以切换到暂停模式,有两种方法:

如果没有设置pipe目标,调用

stream.pause()
方法即可。
如果设置了pipe目标,则需要移除所有的data监听和调用
stream.unpipe()
方法

在Readable对象中有一个

_readableSate
的对象,通过该对象可以得知流当前处于什么模式,如下所示:

readable._readableState.flowing = null,没有数据消费者,流不产生数据
readable._readableState.flowing = true,处于流动模式
readable._readableState.flowing = false,处于暂停模式

为什么使用流取数据

对于小文件,使用

fs.readFile()
方法读取数据更方便,但需要读取大文件的时候,比如几G大小的文件,使用该方法将消耗大量的内存,甚至使程序崩溃。这种情况下,使用流来处理是更合适的,采用分段读取,便不会造成内存的’爆仓’问题。

data事件

在stream提供数据块给消费者时触发,有可能是切换到流动模式的时候,也有可能是调用

readable.read()
方法且有有效数据块的时候,使用如下所示:


const fs = require('fs');

const rs = fs.createReadStream('./appbak.js');
var chunkArr = [],
chunkLen = 0;
rs.on('data',(chunk)=>{
chunkArr.push(chunk);
chunkLen+=chunk.length;
});
rs.on('end',(chunk)=>{
console.log(Buffer.concat(chunkArr,chunkLen).toString());
});

readable事件

当流中有可用数据能被读取时触发,分为两种,新的可用的数据和到达流的末尾,前者