硅基俊宁.
Skills · 技能体系 ↗
← 返回文章

浏览器事件循环与微任务笔记

俊宁 · 日期未详
整理自原官网的历史学习笔记,保留原有译文、引用和署名,不把资料内容认作本人研究或实践成果。本篇有格式适配或明确勘误,详见官网迁移清单。
查看官网迁移清单
浏览器事件循环与微任务笔记封面

微任务队列

Promise 处理程序

.then(() => { ... })
.catch(() => { ... })
.finally(() => { ... })

await 后的 async 函数体

async function asyncFunction() {
  await ...
  // Function body execution following await
}

queueMicrotask() 回调

queueMicrotask(() => {... })

new MutationObserver 回调

const observer = new MutationObserver(() => {... })

浏览器中的任务与微任务

以下以浏览器为范围;Node.js 的事件循环阶段和 nextTick 队列不直接套用此顺序。

特性宏任务微任务
优先级低(下一个事件循环)高(当前宏任务结束后立即执行)
典型场景定时器、用户交互事件Promise、DOM 变更监听
队列处理每次事件循环处理一个每次宏任务结束后清空全部

关键点:理解事件循环的“当前任务中的同步代码 → 清空微任务 → 按需更新渲染 → 后续任务”流程是掌握异步编程的核心。

宏任务(Macrotask)

任务由运行脚本、用户交互或计时器等机制排入任务队列。这里列举浏览器中的常见来源:

渲染更新不是这里所说的普通任务;浏览器在合适时机决定是否更新渲染。

​微任务(Microtask)​

需在当前宏任务结束后立即执行的任务,优先级高于下一个宏任务。常见类型包括:

事件循环(Event Loop)的优先级规则

​执行顺序流程:

​- 同步代码:优先执行主线程的同步任务(如 console.log)。 ​- 微任务队列:当前宏任务执行完毕后,立即清空所有微任务(包括执行过程中新产生的微任务)。 ​- 渲染阶段​(浏览器环境):检查是否需要 UI 渲染(如 DOM 更新)。

​核心规则:

代码示例与执行顺序解析

console.log("1"); // 同步任务
setTimeout(() => console.log("2"), 0); // 宏任务
Promise.resolve().then(() => console.log("3")); // 微任务
console.log("4"); // 同步任务

输出顺序:1 → 4 → 3 → 2

解释:

  1. 同步任务输出 1 和 4。
  2. 当前宏任务(主线程)结束后,执行微任务队列中的 Promise.then,输出 3。
  3. 最后执行宏任务队列中的 setTimeout,输出 2。

常见场景与陷阱

1、​嵌套任务

若任务中产生微任务,任务回调执行完毕并交还控制后,微任务才会在相应检查点执行:

setTimeout(() => {
  console.log("宏任务");
  Promise.resolve().then(() => console.log("微任务"));
}, 0);

输出顺序为:宏任务 → 微任务。

2、​微任务阻塞渲染

长时间运行的微任务会延迟 UI 渲染,因为微任务队列必须在渲染前清空。

参考:MDN:使用微任务与 queueMicrotask。