node.js事件循环由多个阶段组成,定时器回调在timers阶段执行,i/o回调主要在poll阶段处理,关闭回调在close callbacks阶段统一执行,各阶段按特定条件动态流转。

Node.js 的 Event Loop 不是单个队列,而是由多个**阶段(phases)**组成的循环流程,每个阶段负责处理特定类型的回调。I/O 回调、定时器、关闭回调分别在不同阶段执行,且有严格顺序和触发条件。理解它们的流转逻辑,关键在于看清各阶段的职责和进入条件。
定时器回调在 timers 阶段执行
所有通过 setTimeout() 和 setInterval() 设置的回调,只有在到达指定延迟时间后,才会被放入 timers 阶段的队列。事件循环每次进入该阶段时,会检查队列中是否有已到期的定时器任务,并按插入顺序依次执行(FIFO),但不保证绝对精确——实际执行时间受前一阶段耗时、系统调度影响。
- 即使设为
setTimeout(fn, 0),也不会立刻执行,必须等到下一轮 event loop 进入 timers 阶段 - 若 timers 阶段执行耗时过长,会推迟后续阶段(如 poll),进而影响 I/O 响应
- 重复定时器(
setInterval)的下次触发时间,从本次回调开始执行时计算,不是从上一次结束算起
I/O 回调主要在 poll 阶段执行,部分延迟到 pending callbacks 阶段
绝大多数与 I/O 相关的回调(如文件读写完成、TCP 数据到达、HTTP 请求响应等),其 JS 层回调函数是在 poll 阶段执行的。但注意:libuv 底层完成 I/O 操作后,并不会立即调用 JS 回调,而是标记为“就绪”,等待事件循环流转到 poll 阶段再批量处理。
- poll 阶段先处理已就绪的 I/O 回调;若队列为空且没有 setImmediate 待执行,它可能阻塞等待新 I/O 事件
- 某些系统级 I/O 异常(如
ECONNRESET、EMFILE)的回调,会被推迟到 pending callbacks 阶段执行,确保主 I/O 流程稳定 - poll 阶段不执行定时器回调、
setImmediate回调、或socket.on('close', ...)这类关闭回调
关闭回调在 close callbacks 阶段统一执行
资源显式关闭或异常终止触发的回调(例如 socket.on('close', ...)、server.close(...) 的完成回调),全部归入 close callbacks 阶段。这个阶段位于整个循环末端,专门处理“清理型”操作。
- 它只在资源真正释放完毕后才被加入队列,比如 socket 确认断开、文件描述符彻底关闭
- 该阶段优先级低于 poll 和 check,但高于下一轮 timers,因此不会干扰活跃 I/O 或定时调度
- 常见误用:在
socket.destroy()后立刻监听'close',但若连接尚未完全释放,回调仍需等待进入 close callbacks 阶段
阶段流转不是线性走完一遍就结束
事件循环不是固定走完六个阶段再重来。它根据当前状态动态决策:
- 若 timers 阶段执行完,发现仍有到期定时器,会立即再次进入 timers 阶段(不经过中间阶段)
- poll 阶段空闲时,若检测到
setImmediate()待执行,会直接跳转到 check 阶段 - 若 poll 阶段无事可做,且没有待处理的 immediate,又没定时器待触发,事件循环可能退出(进程结束)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











