Node.js中Readable流data/close/end事件的事件循环执行时机
Node.js Readable流data/end/close事件的事件循环执行时机
结合你提供的Node.js 19测试代码和输出,我们可以明确这三个事件在事件循环中的执行逻辑:
一、data事件的执行时机
Readable流的data事件处理函数会被放入process.nextTick微任务队列执行,但触发时机受流的状态影响:
- 当你还未绑定
data事件时,调用push()的数据会被缓存到流的内部缓冲区(测试中前两次push的Buffer 01/02就属于这种情况)。 - 一旦调用
readable.on('data', ...)绑定事件,流会自动切换到流动模式,并立即通过process.nextTick注册一个回调——这个回调会批量读取缓冲区中所有缓存的数据(包括绑定事件前和之后push的Buffer 01/02/03/04),并依次触发data事件。 - 这个批量触发
data事件的process.nextTick回调,会被插入到当前已存在的process.nextTick队列之后(也就是测试中Next tick log 1/2之后),但会优先于后续在主代码中添加的process.nextTick回调(测试中Next tick log 3/4/null)。这就是为什么四个Data received会集中在Next tick log 1/2之后、Next tick log 3/4/null之前输出。
二、end/close事件的执行时机
end事件:当你调用push(null)标记流结束后,流会通过process.nextTick注册一个回调,在所有缓存数据的data事件触发完成后触发end事件。这个回调会被插入到所有主代码中显式添加的process.nextTick回调之后(也就是测试中Next tick log null之后)。close事件:对于你这种手动创建的无底层资源的Readable流,close事件会在end事件触发后同步执行,不需要额外的队列调度,因此会紧跟end事件输出。
从测试输出可以看到,end和close事件既不在setImmediate所在的check宏任务阶段执行,也不属于queueMicrotask队列,而是依赖process.nextTick队列的调度,且在所有显式process.nextTick回调执行完成后、微任务队列执行之前触发。
事件队列归属总结
| 事件 | 执行队列/时机 |
|---|---|
| data | process.nextTick队列,优先级高于queueMicrotask和宏任务 |
| end | process.nextTick队列,位于所有显式添加的process.nextTick回调之后 |
| close | 无额外队列,end事件触发后同步执行(无底层资源场景);若涉及底层资源关闭,会在close callbacks宏任务阶段执行 |
内容的提问来源于stack exchange,提问作者user18363985
相关产品推荐
相关产品推荐

