微任务严格依附宏任务结束节点执行:调用栈清空后立即启动,按FIFO顺序一次性清空当前队列,期间不穿插任何宏任务;执行完全部微任务后才可能触发UI渲染,再取下一个宏任务。

微任务执行流程不是独立运行的,它严格依附于宏任务的结束节点:调用栈清空后,立刻启动,且必须一次性执行完当前队列中所有任务,中途不穿插任何宏任务。
微任务队列的触发时机
它不主动“开始”,只响应一个信号:当前宏任务的同步代码执行完毕、调用栈完全清空。此时 JS 引擎立即检查微任务队列,只要非空,就进入执行阶段。
- 全局脚本执行完 → 触发微任务检查
- setTimeout 回调执行完 → 触发微任务检查
- 点击事件处理函数返回 → 触发微任务检查
- 哪怕只有一行同步代码,结束后也会检查微任务
微任务的入队规则
哪些操作会把任务塞进微任务队列?关键看“注册时机”和“宿主环境约定”:
- Promise.then/catch/finally:回调函数本身被加入微任务队列(注意:new Promise(fn) 中的 fn 是同步执行的)
- async/await:await 后面的语句等价于 .then,属于微任务
- queueMicrotask():显式插入微任务,优先级与 Promise.then 相同
- MutationObserver:DOM 变更监听回调也走微任务
微任务的执行过程
一旦启动,它按先进先出(FIFO)顺序逐个取出并执行,且支持“链式追加”:
- 执行第一个 .then → 里面又调用了 Promise.resolve().then(...) → 新微任务追加到当前队列末尾
- 继续执行下一个 .then,直到队列彻底为空
- 过程中产生的所有新微任务,都纳入本轮执行范围,不会等到下一轮
- 没有“暂停”或“让位”机制:微任务队列不清空,宏任务绝不会重新拿取
和渲染、宏任务的关系
微任务执行完毕后,流程才继续向下走:
- 微任务全部执行完 → 浏览器可能进行一次 UI 渲染(如样式更新、DOM 变化生效)
- 渲染不是强制步骤,取决于是否需要更新视图、帧率限制等
- 渲染完成后,才从宏任务队列中取出下一个任务,开始新一轮循环
- 所以常见模式是:宏任务 → 微任务(全部)→ 渲染(可选)→ 下一宏任务


















