Node.js v11之前版本中setTimeout与Promise.resolve执行顺序困惑
Node.js v10.19.0 事件循环、定时器与微任务执行逻辑解析
先明确核心差异:Node.js v11之前的版本中,同步执行栈清空后,会优先处理微任务队列,再进入事件循环的第一个阶段(timers)——这一点和早期官方文档的描述存在细节偏差,也是你第一个例子不符合预期的关键原因。
第一个示例解析
代码:
Promise.resolve().then(() => console.log('promise')); setTimeout(() => console.log('timeout'));
执行流程:
- 同步代码执行:
Promise.resolve().then()将回调加入微任务队列setTimeout()将回调加入timers阶段队列
- 同步执行栈清空,此时事件循环还未进入第一个阶段:
- Node.js会先清空当前的微任务队列,执行
console.log('promise')
- Node.js会先清空当前的微任务队列,执行
- 微任务队列处理完毕后,进入事件循环的timers阶段,执行
setTimeout的回调,输出timeout
这就是实际结果先输出promise再输出timeout的原因,和早期文档描述的“第一个阶段是timers”的逻辑差异在于:初始同步栈结束后有一个额外的微任务处理时机。
第二个示例解析
代码:
setTimeout(() => console.log('timeout1')); setTimeout(() => { console.log('timeout2'); Promise.resolve().then(() => console.log('promise')); }); setTimeout(() => console.log('timeout3')); setTimeout(() => console.log('timeout4'));
执行流程:
- 同步代码执行:四个
setTimeout的回调全部加入timers阶段队列 - 同步执行栈清空,先处理初始微任务队列(此时为空),进入事件循环的timers阶段
- timers阶段批量执行所有到期的回调:
- 依次执行
timeout1、timeout2(执行时将Promise回调加入微任务队列)、timeout3、timeout4
- 依次执行
- timers阶段所有回调执行完毕后,事件循环进入阶段间的微任务处理环节,清空微任务队列,执行
console.log('promise')
这个流程完全符合文档“Promise会在Event Loop的各个阶段之间执行”的描述,所以结果符合预期。
总结
Node.js v11之前的事件循环逻辑中:
- 初始同步栈清空后:先处理微任务队列,再进入事件循环的第一个阶段(timers)
- 事件循环的各个阶段执行完毕后:处理微任务队列,再进入下一个阶段
这两个不同的微任务处理时机,就是你两个示例结果差异的核心原因。
内容的提问来源于stack exchange,提问作者hunglt.ee
相关产品推荐
相关产品推荐

