·更新于 2026年4月21日· 185 次浏览 Node.js底层原理
Node.js 事件循环:宏任务、微任务与 libuv 线程池
从 phases 到 `process.nextTick`、`queueMicrotask`,理解为何定时器与 Promise 回调顺序如此表现,以及 I/O 回调如何与线程池协作。
作者
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 下延迟抖动来源
“先搞清「谁在什么时候把回调放进队列」,再谈性能优化。”
—— 实践笔记