当监听流的data事件时,流最终会通过resume并调用flow函数进入流动模式模式,即不断的调用read方法读取数据。接下来分析以下几种场景,当dest.write(chunk)返回false时++count会执行几次,注意结合前文的灵魂代码。
场景一:每次_read同步push一次数据
当发生第一次读取,数据同步push到缓冲区,紧接着从缓冲区中读取数据并通过emit data的方式传递到ondata中,如果此时dest.write(chunk)返回false,count++将执行一次,接着由于调用了stream.pause(),while条件state.flowing为false导致stream.read不再被调用,在流重新流动前,count的值不会继续增加。
场景二:每次_read异步push一次数据
当发生第一次读取,异步push的数据将直接通过emit data传递到ondata中,而read函数中的emit由于无法从缓冲区读取数据从而不会触发,同时read返回null导致while循环也相应停止,此种情况下异步push触发data事件后,紧接着的stream.read(0)会继续保持流的流动,当dest.write(chunk)返回false,count++执行一次并将流暂停,紧接着会继续调用一次read,但这次数据将被放入缓冲区且不触发data事件,count++依旧只执行一次。
场景二流暂停一次后再次流动时,数据消耗模式与之前会有所差异,会优先消耗缓冲区数据直至为空时回到之前的模式,但这同样不会导致count++执行多次。
场景三:每次_read多次同步push数据
与场景一类似,只是每次_read会多次往缓冲区写入数据,最终data事件还是依靠从缓冲区读数据后触发。
场景四:每次_read多次异步push数据
同场景二类似,假设在一次_read中有两次异步push,当第一个异步push执行时,data事件触发且其中的dest.write(chunk)返回false,导致count++同时流被暂停,等第二个异步push执行时,由于流已经暂停,数据将写入缓冲区而不是触发data事件,所以count++只执行一次。
场景五:_read操作可能同步或异步push
不管是同步或者异步push,当一次ondata内部将流设置为暂停模式后,flow函数中while条件state.flowing为false将导致stream.read不再调用,异步的push的emit data判断条件同样不再满足,即目前阶段内部不会再有data事件触发直到外部再次间接或直接调用read方法。
以上五个场景是为了分析该问题而模拟的,实际只要能理解第五个场景就能明白所有。
小结
文章最终写出来的内容与我最开始的初衷所偏离,而且自己不知道如何评价这篇文章的好坏,但为了写这文章花了两天业余时间去深入理解stream.Readable却是非常有收获的一件事情,更坚定自己在写文章的路途上可以走的更远。