宏任务和微任务是异步编程中两套独立的任务队列机制,是 Event Loop 调度异步任务的核心依据。微任务的执行优先级远高于宏任务,二者协同工作,保证了 JavaScript 单线程模型下异步代码的有序执行。

定义:由宿主环境(浏览器 /Node.js)调度的异步任务,执行间隔较长,是事件循环中最基础的异步任务
常见类型:
setTimeout、setInterval 定时器
网络请求(AJAX/fetch)
文件 I/O 操作
浏览器用户交互事件(点击、滚动、输入)
浏览器 UI 页面渲染
定义:由 JS 引擎自身调度的异步任务,在当前执行栈清空后立即执行,优先级高于宏任务
常见类型:
Promise.then / catch / finally 回调
queueMicrotask 手动创建微任务
MutationObserver(浏览器环境)
process.nextTick(Node.js 环境,优先级最高)

事件循环的执行遵循固定不可变的优先级规则,是理解异步代码的核心:
执行当前宏任务内部的所有同步代码
同步代码执行完毕后,清空当前所有微任务(微任务队列一次性执行完毕)
浏览器执行页面渲染(可选阶段)
取出下一个宏任务,开始下一轮循环
每执行一个宏任务 → 必须清空所有微任务 → 再执行下一个宏任务
定义:事件循环是 JS 运行时管理宏任务、微任务的循环调度机制
作用:保证任务按优先级顺序执行,永不阻塞主线程,让页面保持流畅响应
通过银行办业务的场景,轻松理解宏任务与微任务的执行逻辑:
取号排队 → 对应宏任务队列,按顺序等待执行
柜员单线程工作 → 同一时间只能为一个人办理业务
主业务办理完成 → 对应宏任务执行完毕
柜员询问是否办理其他业务 → 检查微任务队列
办理附加业务 → 执行所有微任务
附加业务办完 → 微任务清空,为下一个客户服务(执行下一个宏任务)
setTimeout(() => {
console.log(1); // 宏任务
});
new Promise((resolve) => {
console.log(2); // 同步任务(Promise 构造函数同步执行)
resolve();
}).then(() => {
console.log(3); // 微任务
});
console.log(4); // 同步任务执行所有同步任务:依次输出 2、4
清空微任务队列:执行 Promise.then 输出 3
执行下一个宏任务:执行定时器输出 1
2 → 4 → 3 → 1
console.log(1); // 同步任务
setTimeout(() => {
console.log(2); // 宏任务内部同步代码
new Promise((resolve) => {
console.log(3); // 同步任务
resolve();
}).then(() => {
console.log(4); // 微任务
});
});
new Promise((resolve) => {
console.log(5); // 同步任务
resolve();
}).then(() => {
console.log(6); // 微任务
});
setTimeout(() => {
console.log(7); // 宏任务内部同步代码
new Promise((resolve) => {
console.log(8); // 同步任务
resolve();
}).then(() => {
console.log(9); // 微任务
});
});执行全局同步任务:输出 1、5
清空全局微任务队列:执行 Promise.then 输出 6
执行第一个宏任务(定时器): 内部同步代码输出 2、3 → 清空微任务输出 4
执行第二个宏任务(定时器): 内部同步代码输出 7、8 → 清空微任务输出 9
1 5 6 2 3 4 7 8 9
执行优先级:同步任务 > 微任务 > 宏任务
Promise 构造函数内的代码是同步任务,只有 .then/catch/finally 是微任务
每一个宏任务执行完成后,都会一次性清空所有微任务,再进入下一轮循环
宏任务由宿主环境调度,微任务由 JS 引擎调度,是异步编程的核心基础