setTimeout和setInterval回调属于宏任务,在事件循环timers阶段执行;它们被注册进底层定时器系统(如libuv最小堆),到期后进入timers队列,需等待同步代码和微任务执行完毕,于下一轮timers阶段按序执行,实际延迟≥设定值。

setTimeout 和 setInterval 的回调函数都属于宏任务,统一归入事件循环的 timers 队列,在事件循环的 timers 阶段 执行。
它们都在 timers 阶段被处理
浏览器和 Node.js 的事件循环都有明确的 timers 阶段,专用于执行到期的定时器回调:
- 调用
setTimeout(fn, ms)或setInterval(fn, ms)时,运行时会将回调注册进底层定时器系统(如 libuv 的最小堆); - 当时间到达,回调不会立即执行,而是被标记为“到期”,并排队进入宏任务队列中的 timers 子队列;
- 只有当事件循环进入 timers 阶段,且当前同步代码和所有微任务均已执行完毕后,这些回调才被批量取出、按注册顺序依次执行。
实际延迟 ≥ 设定值
由于依赖事件循环调度,定时器的实际执行时机存在天然延迟:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
setTimeout(fn, 0)不代表“立刻执行”,它仍需等待当前宏任务结束 + 微任务清空 + 进入下一轮事件循环的 timers 阶段; -
setInterval(fn, 10)也不保证每 10ms 精确执行一次:若fn执行耗时超过 10ms,后续回调会积压,出现“连续执行”现象,而非严格间隔; - 频繁或长时间阻塞的同步代码(如大型循环、复杂计算)会推迟 timers 阶段的开始,进一步拉长回调执行时间。
与其它宏任务的关系
timers 队列只是宏任务的一种来源,它与其他宏任务并列但互不干扰:
立即学习“Java免费学习笔记(深入)”;
- UI 渲染、I/O 回调、
setImmediate(Node.js)、用户事件(如 click)各自归属不同事件循环阶段; - 同一轮事件循环中,timers 阶段只处理 timers 队列,不会穿插执行 poll 或 check 阶段的任务;
- 多个
setTimeout和setInterval注册的回调,按到期时间顺序排列,到期时间相同时,按注册先后执行。
不是微任务,也不参与微任务竞争
这点容易混淆,需特别注意:
- Promise.then、
queueMicrotask、process.nextTick属于微任务,在当前宏任务结束后、下一个宏任务开始前集中执行; - 即使
setTimeout(fn, 0)和Promise.then几乎同时“就绪”,后者一定先执行; - 定时器回调永远不会插队到微任务中间,也不会被微任务“打断”——它必须等完整的一轮微任务清空后,才能轮到 timers 阶段。

















