关键在于每完成一个宏任务后立即清空全部微任务;微任务由JS引擎产生(如Promise.then),宏任务由宿主环境调度(如setTimeout);事件循环按同步→微任务→宏任务三步执行,微任务队列会递归清空直至为空才取下一个宏任务。

要正确分析宏任务与微任务的执行顺序,关键不是死记队列名称,而是抓住事件循环中“每完成一个宏任务,就立刻清空全部微任务”这一不可跳过的环节。只要同步代码走完、微任务队列不空,浏览器或 Node 就不会去碰下一个宏任务。
先识别任务类型:看来源,不看延迟时间
很多初学者误以为 setTimeout(..., 0) 是“马上执行”,其实它仍是宏任务——0 毫秒只是尽快入队,不改变任务性质。判断依据是任务由谁发起:
-
微任务:JS 引擎自己产生的,比如
Promise.then、queueMicrotask()、MutationObserver回调;async/await中await后面的代码也属于微任务 -
宏任务:宿主环境(浏览器或 Node)调度的,比如
setTimeout、setInterval、script标签整体、用户点击事件、fetch回调、UI 渲染
按事件循环三步走:同步 → 微任务 → 宏任务
每次循环只推进一次,但微任务会“连打”到底:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 执行当前所有同步代码(包括脚本顶层语句)
- 一旦同步代码结束,立即检查微任务队列:逐个取出执行,过程中新产生的微任务(如
then里又返回一个Promise)会追加到队尾,继续执行,直到队列彻底为空 - 微任务清空后,才从宏任务队列取**第一个**任务执行(注意:只取一个),然后重复第二步
注意嵌套和动态生成:微任务可递归,宏任务不能“插队”
微任务队列是“深度优先”的:一个 Promise.then 里再调用 Promise.resolve().then,新微任务会排在当前队列末尾,但仍在本轮循环内执行完。而宏任务哪怕先注册,也得等前面所有宏任务(及它们触发的微任务)跑完才能轮到。
立即学习“Java免费学习笔记(深入)”;
- 例如两个
setTimeout都设为 0,先注册的那个一定先执行(FIFO) - 但若第一个
setTimeout的回调里又产生微任务,这些微任务会在第二个setTimeout执行前全部跑完
实际调试技巧:加标记 + 分步验证
面对复杂嵌套,别靠脑算。推荐做法:
- 给每个
console.log加明确前缀,比如'[sync]'、'[micro1]'、'[macro2]' - 把代码拆成小块,逐步增加任务,观察输出变化
- 用
queueMicrotask替代Promise.resolve().then可避免 Promise 状态链干扰,更纯粹地测试微任务行为

















