javascript中settimeout和queuemicrotask执行顺序不同,因前者属宏任务、后者属微任务;宏任务每轮只执行一个,而每次宏任务结束后立即清空全部微任务,故queuemicrotask总在settimeout之前执行。

JavaScript 的 Event Loop 区分 setTimeout 和 queueMicrotask 的核心,在于它们被推入的任务队列类型不同,以及事件循环在每个周期中处理这两类任务的时机和规则完全不同。
任务归属:宏任务 vs 微任务
setTimeout 回调属于宏任务,会被放入宏任务队列(Macrotask Queue);
queueMicrotask 的回调属于微任务,会被立即加入微任务队列(Microtask Queue)。
这个归属差异直接决定了它们的执行优先级和插入时机:
- 宏任务队列每次只取一个任务执行(如主脚本、setTimeout、setInterval、UI 渲染等)
- 微任务队列在**每次宏任务执行完后**,会一次性清空所有当前排队的任务
- 因此,哪怕
queueMicrotask在setTimeout之后几毫秒才调用,它的回调仍会在该轮宏任务结束后、下一轮宏任务开始前执行
执行时机:一次宏任务后必清空微任务
事件循环流程固定为:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 执行当前宏任务(比如主 script 或某个 setTimeout 回调)
- 检查微任务队列 → 若非空,逐个执行直到清空
- (浏览器环境)可选执行 UI 渲染
- 从宏任务队列取出下一个任务,重复上述流程
这意味着:
– queueMicrotask(cb) 不管写在哪儿,只要所在宏任务还没结束,它注册的回调就一定排在“当前宏任务结束后的第一时间”执行;
– setTimeout(cb, 0) 即使延迟为 0,也要等到当前宏任务 + 所有微任务都跑完,再等待下一轮事件循环才可能执行。
实际行为对比示例
看这段代码:
console.log('A');setTimeout(() => console.log('B'), 0);
queueMicrotask(() => console.log('C'));
console.log('D');
输出顺序是:A → D → C → B
原因很清晰:
- A 和 D 是同步代码,立刻执行
- C 被加入微任务队列,同步代码一结束就执行
- B 被加入宏任务队列,要等“当前宏任务(主脚本)+ 所有微任务(C)”全部完成,才轮到它
使用场景建议
根据执行时机差异,可以这样选择:
- 用
queueMicrotask:需要“在本轮同步逻辑之后、但又不触发重排/重绘之前”执行轻量逻辑,比如统一收集中间状态、提前调度 DOM 更新、避免嵌套 Promise.then 的开销 - 用
setTimeout(..., 0):需要确保已发生 UI 渲染、或让出主线程给其他高优任务(如用户输入)、或实现真正意义上的“下一帧之后”延迟(注意:浏览器对 0ms 有最小约 4ms 限制)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










