setTimeout是宏任务,因其回调被放入宏任务队列,须等同步代码和所有微任务执行完毕后,在下一轮事件循环中执行;规范明确将其与setInterval、I/O等同列为宏任务,且0ms延迟也至少等待4ms并受主线程空闲影响。

setTimeout 是宏任务,不是微任务。它的回调函数会被放入宏任务队列,在当前事件循环的同步代码和所有微任务执行完毕后,才进入下一轮事件循环执行。
为什么 setTimeout 一定是宏任务?
- 浏览器和 Node.js 的事件循环规范明确将 `setTimeout`、`setInterval`、I/O 回调、UI 渲染等归为宏任务。 - 它的执行时机严格遵循: 同步代码 → 当前宏任务内的全部微任务(如 Promise.then)→ 渲染(浏览器环境)→ 下一个宏任务(比如 setTimeout 回调) - 示例验证:console.log('A');
setTimeout(() => console.log('C'), 0);
Promise.resolve().then(() => console.log('B'));
console.log('D');
setTimeout 的延迟时间怎么算?
- 第二个参数(毫秒数)**不是精确等待时长**,而是“至少等待这么久”: - 浏览器强制最小延迟为 4ms(HTML5 标准),即使写 `setTimeout(fn, 0)`,实际也至少延后约 4ms。 - 真实触发时间 = 代码注册时刻 + 延迟参数 + 主线程空闲等待时间。 - 关键影响因素: - 当前执行栈是否繁忙(比如有长循环阻塞); - 微任务队列是否积压; - 浏览器节流策略(如页面后台运行时定时器可能被大幅延迟); - 系统负载与调度精度。和 Promise 相比,执行优先级差在哪?
- `Promise.then` 是微任务,会在本轮事件循环末尾立即执行; - `setTimeout` 是宏任务,必须等到下一轮事件循环开始时才检查是否到期; - 所以哪怕 `setTimeout(..., 0)` 和 `Promise.resolve().then(...)` 几乎同时注册,后者一定先执行。常见误区澄清:
✘ “0ms 就立刻执行” —— 实际要等同步+微任务完成;
✘ “setTimeout 比 Promise 快” —— 完全相反,微任务永远优于宏任务;
✘ “延迟时间可精准控制” —— 只能保证下限,不能保证上限。


















