什么是流?
流是node.js最重要的组成和设计模式之一,可以做到实时处理。
流的重要性
读取一个文件可以分为两种方式
1、读取全部文件到缓存后,再处理。
这样的问题是:1、需要的时间需要加倍。2、内存可能溢出。
2、通过流边读取,边处理。这样可以提升时间效率,降低空间占用。
所以要实现大文件的高效率读取,防止内存爆掉,用流是很有必要,而不光如此,像是网络请求通信等实时性高的,如果等服务器组合好再返回数据,那么时效性太差,而流刚好可以处理这个场景,服务器可以边产生数据边返回。
而流的好处不光如此,流还具有组合性
什么是流的组合性?
流具有pipe方法,这个方法的作用是把不同的处理单元连接起来,组合成一个流的管道,比如读取一个文件,在第一个流里面读取,然后通过pipe方法传送给第二个流的处理单元压缩,再传送给第三个流的处理单元加密,pipe在这其中的作用就是把这些流链接起来,组成一个管道。
流的分类
可读流
一个可读流代表一个数据源,在node.js中,可以使用stream模块提供的Readable抽象类来实现。
从流中如何读取数据?
获取数据的方式有两种:1、非流动模式。2、流动模式。
非流动模式:
从可读流中读取数据的默认方式都是添加一个对于readable事件的监听器,在读取新的数据时进行通知,然后在一个循环里读取所有的数据,直到内部的缓存被清空,这个可以通过read()方法来实现,该方法能同步读取缓存中的数据,并返回一个buffer或者string对象表示数据块,read()方法的使用如下:
readable.read()
使用该方法,数据是根据需要从流中被拉取得。
数据可以在readable的事件监听器中被读取到,该事件会在新数据可读时被触发。当内存中没有更多数据可读时,read()方法会返回null,这个时候就必须等待readable事件再次触发,告诉我们有新的数据可以读取或者等待end事件,告诉我们整个可读流已经结束了,二进制情况下还可以指定read方法的size值,表示想要读取数据的大小,在实现网络协议(可以读取数据的头部信息,获取消息类型)或者解析特定数据格式的时候,这一点非常有用。在二进制模式下,可以通过调用setEncoding(),给可读流设置一个有效的编码格式,从而直接读取到字符串而不是buffer值
流动模式:
给data事件添加一个监听器,这就是流动模式的流读取,该模式下数据不是通过read来拉取,相反只要流中数据可读,便会立即推送到data事件的监听器。
这里需要注意的是:流动模式继承了旧版本(stream1)的流接口,其在控制数据流上灵活性不大(不能按需读取数据),而在stream2中流动模式不是默认的工作模式,如果想启用,需要为data事件添加监听器或者显式调用resume方法。可以通过pause()方法临时组织data事件,将接受的数据临时存放到内部缓存中,但是不会导致流转回非流动模式。
实现可读流
需要创建一个新的类,继承stream.Radable的原型,具体的流实例必须提供对于_read方法的实现。一个流的实现主要在于,生产数据和消费数据之间的协调,当生产过快的时候,缓存不足需要节制生产,等待消费数据消费掉缓存,否则会造成数据丢失
Readable类内部会调用_read方法,紧接着会调用push方法将数据填充到缓存中。
什么时候可以触发_read方法?
1、注册data事件。2、read()。3、resume()。以上三种只可以触发一次_read(),之后的read需要this.push触发