process.nextTick、Promise、setImmediate 与 setTimeout 的关系

解释 Node.js 中 process.nextTick、Promise 微任务、setImmediate 和 setTimeout 的执行优先级与常见输出顺序。

#type / synthesis #status / growing #tech / dev / backend #resource / nodejs #resource / javascript

[!info] related notes

process.nextTick、Promise、setImmediate 与 setTimeout 的关系

范围

这篇只处理 Node.js 宿主里的一个高频面试混淆点:

  • process.nextTick
  • Promise 微任务
  • setImmediate
  • setTimeout(fn, 0)

它不重复解释什么是事件循环本身,基础部分看 Node.js 事件循环阶段

为什么要放在一起理解

很多人知道“Promise 比 setTimeout 早”,但一到 Node.js 场景就会混乱,因为这里多了两个关键变量:

  • process.nextTick
  • setImmediate

如果不把四者放到同一个调度模型里,很容易把输出顺序背成死口诀。

依赖路径 / 调用链 / 演进链

先建立一个足够稳的顺序:

同步代码

process.nextTick

Promise 微任务

事件循环中的 timers / poll / check ...

然后再记:

  • setTimeout(fn, 0) 属于 timers
  • setImmediate 属于 check

对比与易混淆点

项目更接近什么常见优先级理解备注
process.nextTickNode 宿主特有队列最高滥用会饿死事件循环
Promise.then标准微任务低于 nextTick,高于下一轮阶段任务浏览器和 Node 都有
setTimeout(fn, 0)timers 阶段要等进入 timers不是“立即执行”
setImmediatecheck 阶段常在 I/O 回调后更早可见不是所有场景都稳压过 setTimeout

一个常见顺序题

console.log('start');

setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));

Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));

console.log('end');

更稳的分析是:

start
end
nextTick
promise
timeout / immediate(顶层主模块里别背死)

为什么 nextTick 更危险

因为它优先级太高。

如果递归调用:

function loop() {
  process.nextTick(loop);
}

loop();

I/O、timer 和其他阶段任务就可能一直拿不到执行机会。

为什么 I/O 回调里经常先看到 setImmediate

因为 I/O 回调通常和 poll -> check 的切换更近。

所以在 I/O 回调里这一组代码:

setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));

通常更容易先看到 immediate

创建于 2026/5/21 更新于 2026/5/27