Node.js Stream ondata触发时机与顺序的探索

2020-06-17 05:47:54易采站长站整理

上次写Stream pipe细节时,在源码中发现一段无用逻辑,由此引发了对Stream data事件触发时机与顺序的探索。

无用逻辑

当时研究pipe细节是基于Node.js v8.11.1的源码,其中针对上游的ondata事件处理有如下一段代码:


// If the user pushes more data while we're writing to dest then we'll end up
// in ondata again. However, we only want to increase awaitDrain once because
// dest will only emit one 'drain' event for the multiple writes.
// => Introduce a guard on increasing awaitDrain.
var increasedAwaitDrain = false;
src.on('data', ondata);
function ondata(chunk) {
debug('ondata');
increasedAwaitDrain = false;
var ret = dest.write(chunk);
if (false === ret && !increasedAwaitDrain) {
if (((state.pipesCount === 1 && state.pipes === dest) ||
(state.pipesCount > 1 && state.pipes.indexOf(dest) !== -1)) &&
!cleanedUp) {
debug('false write response, pause', src._readableState.awaitDrain);
src._readableState.awaitDrain++;
increasedAwaitDrain = true;
}
src.pause();
}
}

重点关注

increasedAwaitDrain
变量,理解这个变量期望达到什么目的,然后仔细阅读代码,会发现
if (false === ret && !increasedAwaitDrain)
语句中
increasedAwaitDrain
变量肯定是false,因为前一行才将该变量赋值为false,这样一来这个变量就变得毫无意义。


increasedAwaitDrain = false;
var ret = dest.write(chunk);
if (false === ret && !increasedAwaitDrain) {}

以上就是关键的三行代码,因为Node.js是单线程且

dest.write(chunk)
内部没有修改变量
increasedAwaitDrain
的值,那么if语句中
increasedAwaitDrain
的值肯定还是false,即
increasedAwaitDrain
相关逻辑没有达到所期望的目标。

无用代码出现的原因

前段虽已经分析出

increasedAwaitDrain
没起到作用,但作者为什么写了这样一段逻辑呢?其实在定义
increasedAwaitDrain
语句的上方,作者说可能存在这样一种情况:“当我们接收到一次上游的ondata事件并尝试将数据写到下游时,上游可能同时又有一个data事件触发,而这两个ondata的数据在写入下游时可能都返回false,从而导致
src._readableState.awaitDrain++
执行两次”。