Node.js 事件循环机制:Promise、nextTick、setTimeout 与 setImmediate 执行顺序详解

作者:岩茶

时间:2026-10-23

浏览:156

本文深入解析 Node.js 事件循环机制,详细阐述同步代码、process.nextTick、Promise.then、setTimeout 及 setImmediate 的执行优先级。通过具体代码示例,展示宏任务与微任务的调度顺序,帮助开发者准确掌握异步回调的执行逻辑。

文章目录

本文旨在深入解析 Node.js 中 Promise.then、process.nextTick、setTimeout 以及 setImmediate 的执行顺序,并提供具体的代码示例供参考。

典型代码执行顺序示例

首先,通过一个典型的代码片段来引出问题:


setImmediate(function(){
  console.log(1);
},0);
setTimeout(function(){
  console.log(2);
},0);
new Promise(function(resolve){
  console.log(3);
  resolve();
  console.log(4);
}).then(function(){
  console.log(5);
});
console.log(6);
process.nextTick(function(){
  console.log(7);
});
console.log(8);

这段代码执行后的输出顺序是什么?

正确的输出结果如下:

3 4 6 8 7 5 2 1

宏任务与微任务概念解析

在分析输出结果之前,我们需要明确 Node.js 事件循环中的几个核心概念:

宏任务(macro-task)包括:脚本整体代码、setTimeout、setInterval、setImmediate、I/O 操作以及 UI 渲染。

微任务(micro-task)包括:process.nextTick、原生 Promise、Object.observe 以及 MutationObserver。

事件循环执行步骤详解

第一步,执行脚本整体代码,具体执行流程如下:

  • 注册一个宏任务:setImmediate。
  • 注册一个宏任务:setTimeout。
  • 注册一个微任务:Promise.then 的回调函数,并继续执行同步代码 console.log(3); resolve(); console.log(4);。此时控制台输出 3 和 4。尽管 resolve() 已被调用,但由于当前同步代码尚未执行完毕,Promise.then 的回调不会立即执行。
  • 执行 console.log(6),控制台输出 6。
  • 注册一个微任务:process.nextTick。
  • 执行 console.log(8),控制台输出 8。
  • 经过上述同步代码的执行阶段,控制台已依次输出 3、4、6、8。

第二步,由于微任务的优先级高于宏任务,系统开始处理微任务队列。

当前微任务队列中包含两个任务,根据优先级规则,process.nextTick 的优先级高于 Promise.then。

因此,先执行 process.nextTick 回调,输出 7;随后执行 Promise.then 回调,输出 5。

第三步,当微任务队列执行完毕后,开始执行宏任务。由于 setTimeout 的优先级高于 setImmediate,因此先执行 setTimeout 回调,输出 2;最后执行 setImmediate 回调,输出 1。

整个过程看似同步执行,但实际上是基于 Event Loop(事件循环)机制进行的异步调度。

新版 Node.js 中的特殊行为

关于微任务与宏任务的执行顺序,可以参考《深入浅出 Node.js》中的一个经典示例:


//加入两个nextTick的回调函数
process.nextTick(function () {
  console.log('nextTick延迟执行1');
});
process.nextTick(function () { 
  console.log('nextTick延迟执行2');
});
// 加入两个setImmediate()的回调函数
setImmediate(function () {
  console.log('setImmediate延迟执行1'); 
  // 进入下次循环 
  process.nextTick(function () {
    console.log('强势插入');
  });
});
setImmediate(function () {
  console.log('setImmediate延迟执行2'); 
});

console.log('正常执行');

运行该代码,得到的结果如下:

正常执行 nextTick延迟执行1 nextTick延迟执行2 setImmediate延迟执行1 setImmediate延迟执行2 强势插入

在新版 Node.js 中,process.nextTick 执行完毕后,会遍历并执行所有 setImmediate 回调,直到 setImmediate 队列清空后才跳出当前循环。因此,在两个 setImmediate 执行完毕后,队列中仅剩第一个 setImmediate 内部注册的 process.nextTick,最终输出“强势插入”。

观察者优先级机制

关于优先级的另一个清晰版本如下:

观察者优先级机制。

在每次事件循环检查中,各阶段观察者的优先级分别为:

idle 观察者 > I/O 观察者 > check 观察者。

idle 观察者对应:process.nextTick。

I/O 观察者对应:常规 I/O 回调,如网络、文件、数据库 I/O 等。

check 观察者对应:setTimeout 和 setImmediate,其中 setTimeout 优先级高于 setImmediate。

执行优先级总结

总结。

  • 同步代码的执行优先级高于异步代码;
  • new Promise(fn) 中的 fn 函数是同步执行的;
  • 优先级顺序为:process.nextTick > Promise.then > setTimeout > setImmediate。

以上就是本文的全部内容,希望这些解析能对您的学习有所帮助,欢迎继续支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章