·更新于 2026年4月21日· 185 次浏览 Node.js底层原理

Node.js 事件循环:宏任务、微任务与 libuv 线程池

从 phases 到 `process.nextTick`、`queueMicrotask`,理解为何定时器与 Promise 回调顺序如此表现,以及 I/O 回调如何与线程池协作。

Node.js 事件循环:宏任务、微任务与 libuv 线程池
ZHOU YI

作者

ZHOU YI

Node.js 将 JavaScript 执行与 I/O 解耦:主线程运行 V8 与用户代码,文件、网络等异步操作多由 libuv 在线程池或各平台异步 API 上完成,完成后再把回调投递回事件循环。

事件循环阶段(简化)

  • timers:setTimeout / setInterval 到期的回调
  • pending callbacks:部分系统级回调
  • poll:拉取新的 I/O 事件;可能阻塞等待
  • check:setImmediate
  • close callbacks:如 socket.on("close")

每个阶段之间会处理微任务队列:先清空 nextTick 队列,再处理其它 microtask(如 Promise then)。因此同一次宏任务结束后,微任务总是先于下一阶段宏任务执行。

js
setTimeout(() => console.log('timeout'), 0)
Promise.resolve().then(() => console.log('promise'))
process.nextTick(() => console.log('tick'))
// 输出顺序:tick → promise → timeout

实践建议

  • 避免在 nextTick 中递归排队导致 I/O 饥饿
  • CPU 密集任务应交给 Worker Threads 或拆分到子进程
  • 理解 poll 阶段行为有助于解释高 QPS 下延迟抖动来源

先搞清「谁在什么时候把回调放进队列」,再谈性能优化。

—— 实践笔记

Guestbook

留言

若这篇文章也曾停在你心上,留一行字吧,我会看的。

先确认一下邮箱

多这一步,是为了少些机器骚扰,也让我能更踏实地读每一条真人写下的字。验证码 10 分钟内有效;同一邮箱 60 秒内只能发一封。

本文留言

0已加载 0

这里还静悄悄的——愿意做第一个留下脚印的人吗?