streamtypeReadable,Writable,Duplex,TransformReadableStreamReadable可以看成是消息队列的生产者。Readable有两种模式,流动和非流动。StreamingModeStreaming模式用户监听数据事件,可以自行决定暂停和恢复。读取时,先将数据写入缓冲区,如果缓冲区值高于highWaterMark,则停止读取。source=>buffer=>customer,比如把水从一个大水箱A引到另一个水箱B,我们在水箱A上接一个管道,在管道的另一端接一个水桶(缓冲池),接出水口水桶另一端的管道流向B,B有一个开关。一旦桶达到highWaterMark,TankA将暂停填充桶。Non-flowingmode在non-flowingmode下,用户需要自己读取buffer的数据,读取的大小由自己决定,所以不再需要pause和resume。readable事件触发后,用户可以调用read(size)读取数据。可读事件触发的条件是数据到达缓冲池,所以需要给消费者加条件锁,避免消费不及时带来的问题。WritableStream的原理和ReadableStream类似,这里不再赘述。pipeStream有自己的管道(pipeline),所以流之间可以通过管道相互连接。您可以将可读流直接连接到可写流。constreadable=fs.createReadableStream('/tmp/input.txt');constwritable=fs.createWritableStream('/tmp/output.txt');可读管道(可写);ReadableStream是producer,WritableStream是Consumers不能本末倒置的写成writable.pipe(readable)双工流DuplexTransformDuplexTransformDuplexreadandwritestreams都绑定一个subject,就是这种Stream既有ReadableStream也有WritableStream,但是这两个流是独立的,互不相关的,相当于两个对象继承自一个对象。转换这个流非常有用。有时你得到一个WritableStream,你需要立即将WritableStream转换为一个ReadableStreampipe到另一个pipe(上面说了WritableStream不能作为producer)。Transform需要实现Transform。prototype._transform方法const{Transform}=require('stream');classTransformStreamextendsTransform{constructor(options){super(options);}_transform(数据,编码,回调){回调(空,数据);}}举个栗子:upyundump镜像下载上传,下载的是WritableStream,上传的需要ReadableStream。如果不使用transform,就得先保存getFile的结果,创建可读流,然后才有可读流管道。如果使用Transformstream,会很简单。asyncfunctionfoo(){try{consttransform=newTransformStream();//这里不能awaitTransform,只是将流从可写转为可读,没有管道数据constpass=client.getFile(path,transform);//这里不能await,如果使用awaitupyungetFile返回错误,将无法处理constpipe=transform。pipe(request({uri:someuri,method:'post',headers:{'Content-Type':'image/jpeg'},encoding:null,});constthrough=awaitpass;//参见hanldegetFilepromiseupyunnodesdk源码.if(!through){//可能getFile不存在或者upyun服务限制上传returnfalse;}constresponse=awaitpipe;//处理管道请求}catch(err){console.log(err);}}
