Node.js事件循环中微任务执行位置及阶段优先级问询
Node.js事件循环与微任务优先级疑问
这是Node事件循环:
┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ pending callbacks │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ idle, prepare │ │ └─────────────┬─────────────┘ ┌───────────────┐ │ ┌─────────────┴─────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └─────────────┬─────────────┘ │ data, etc. │ │ ┌─────────────┴─────────────┐ └───────────────┘ │ │ check │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ └──┤ close callbacks │ └───────────────────────────┘
我了解Node采用V8 JS引擎,且V8拥有可被嵌入者替换或扩展的自有事件循环。例如在Chrome中存在macrotask和microtask队列(microtask队列优先级高于macrotask队列),主线程调用栈为空时事件循环会从这些队列推送回调。
可通过queueMicrotask函数手动将微任务加入microtask队列,我在Node中测试该函数可正常运行。
我编写了如下代码测试Node事件循环的优先级:
const hello_world =() => { console.log("Hello World 2"); }; queueMicrotask(hello_world); setTimeout( () => { console.log("Hello World 3"); }, 0 ); console.log("Hello World 1"); /* OUTPUT: Hello World 1 Hello World 2 Hello World 3 */
从输出可知微任务优先级高于timers(在Chrome事件循环中属于macrotask),但我有两个疑问:
- 在Node事件循环中,微任务被入队到哪个阶段?是否有专属阶段还是与其他回调混合?
- Node事件循环的各阶段优先级顺序是怎样的?
问题解答
1. Node.js中微任务的处理时机
Node.js里并没有为微任务划分独立的事件循环阶段,而是在每个事件循环阶段执行完毕后,都会清空所有微任务队列(包括queueMicrotask、process.nextTick、Promise回调等),再进入下一个阶段。
需要注意的是,process.nextTick的优先级比普通微任务(比如queueMicrotask、Promise.then)更高,会在其他微任务之前被执行,但它们都属于同一类需要在阶段间隙处理的任务。
2. Node.js事件循环各阶段的优先级顺序
Node.js事件循环的阶段严格按照以下顺序依次执行,每个阶段会先处理完该阶段所有可执行的回调,再处理微任务队列,然后进入下一个阶段:
- timers:执行
setTimeout、setInterval的到期回调 - pending callbacks:处理系统操作的回调(比如TCP错误回调)
- idle, prepare:仅内部使用,用户代码不会涉及
- poll:检索新的I/O事件;执行与I/O相关的回调;如果没有待处理的回调,会在此阶段等待新的事件触发
- check:执行
setImmediate的回调 - close callbacks:执行关闭相关的回调(比如
socket.on('close', ...))
另外,每次事件循环启动时,会先执行所有process.nextTick队列中的任务,再开始进入上述阶段。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

