setImmediate 总是比 setTimeout(0) 先执行,因其在 check 阶段(poll 阶段结束后立即执行)运行,而 setTimeout(0) 回调属于 timers 阶段,需等待下一轮事件循环。

在 I/O 事件回调中,setImmediate 总是比 setTimeout(0) 先执行。这不是偶然,而是 Node.js 事件循环阶段设计决定的确定性行为。
它发生在 check 阶段,紧接 poll 结束之后
当 fs.readFile、net.connect 等 I/O 操作完成,其回调函数在 poll 阶段 执行;一旦该回调结束,事件循环立刻进入 check 阶段,所有已注册的 setImmediate 回调就在此刻运行。
- setTimeout(0) 的回调则被放入 timers 阶段,要等到下一轮事件循环才可能执行
- 哪怕只差一个 tick,setImmediate 实际少走一整轮循环
- 这个顺序稳定、可预测,不随系统负载变化
典型代码验证执行顺序
以下代码每次运行都输出 immediate → timeout:
fs.readFile(__filename, () => {
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
});
- I/O 回调本身在 poll 阶段运行
- 紧接着进入 check 阶段 → 执行 setImmediate
- 再下一轮循环才到 timers 阶段 → 执行 setTimeout
为什么不是“立刻”,而是“检查之后”
名字里的 “Immediate” 容易误解,它实际含义是:在 poll 阶段清空后、第一时间进入 check 阶段执行。
- 它不会打断当前正在运行的 I/O 回调
- 也不插队到当前同步任务中间(这点和 process.nextTick 不同)
- 只保证排入 check 队列,并在该阶段按注册顺序执行
适用场景:I/O 后轻量级后续处理
正因为它的执行时机卡在 I/O 完成之后、下一轮定时器之前,特别适合:
- 资源清理(如关闭临时句柄)
- 状态同步(更新缓存、刷新指标)
- 分片长任务的下一段调度(避免阻塞 poll)


















