源本科技 | 码上会

宏任务与微任务

2026/04/11
2
0

引言

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

任务分类

宏任务

  • 定义:由宿主环境(浏览器 /Node.js)调度的异步任务,执行间隔较长,是事件循环中最基础的异步任务

  • 常见类型

    • setTimeoutsetInterval 定时器

    • 网络请求(AJAX/fetch)

    • 文件 I/O 操作

    • 浏览器用户交互事件(点击、滚动、输入)

    • 浏览器 UI 页面渲染

微任务

  • 定义:由 JS 引擎自身调度的异步任务,在当前执行栈清空后立即执行,优先级高于宏任务

  • 常见类型

    • Promise.then / catch / finally 回调

    • queueMicrotask 手动创建微任务

    • MutationObserver(浏览器环境)

    • process.nextTick(Node.js 环境,优先级最高)


执行顺序

标准执行流程

事件循环的执行遵循固定不可变的优先级规则,是理解异步代码的核心:

  1. 执行当前宏任务内部的所有同步代码

  2. 同步代码执行完毕后,清空当前所有微任务(微任务队列一次性执行完毕)

  3. 浏览器执行页面渲染(可选阶段)

  4. 取出下一个宏任务,开始下一轮循环

核心规则

每执行一个宏任务 → 必须清空所有微任务 → 再执行下一个宏任务

事件循环

  • 定义:事件循环是 JS 运行时管理宏任务、微任务的循环调度机制

  • 作用:保证任务按优先级顺序执行,永不阻塞主线程,让页面保持流畅响应


生活化案例

通过银行办业务的场景,轻松理解宏任务与微任务的执行逻辑:

  • 取号排队 → 对应宏任务队列,按顺序等待执行

  • 柜员单线程工作 → 同一时间只能为一个人办理业务

  • 主业务办理完成 → 对应宏任务执行完毕

  • 柜员询问是否办理其他业务 → 检查微任务队列

  • 办理附加业务 → 执行所有微任务

  • 附加业务办完 → 微任务清空,为下一个客户服务(执行下一个宏任务)


执行顺序分析

基础示例

setTimeout(() => {
    console.log(1); // 宏任务
});

new Promise((resolve) => {
    console.log(2); // 同步任务(Promise 构造函数同步执行)
    resolve();
}).then(() => {
    console.log(3); // 微任务
});

console.log(4); // 同步任务

执行步骤

  1. 执行所有同步任务:依次输出 24

  2. 清空微任务队列:执行 Promise.then 输出 3

  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. 执行全局同步任务:输出 15

  2. 清空全局微任务队列:执行 Promise.then 输出 6

  3. 执行第一个宏任务(定时器): 内部同步代码输出 23 → 清空微任务输出 4

  4. 执行第二个宏任务(定时器): 内部同步代码输出 78 → 清空微任务输出 9

最终结果

1 5 6 2 3 4 7 8 9


总结

  1. 执行优先级:同步任务 > 微任务 > 宏任务

  2. Promise 构造函数内的代码是同步任务,只有 .then/catch/finally 是微任务

  3. 每一个宏任务执行完成后,都会一次性清空所有微任务,再进入下一轮循环

  4. 宏任务由宿主环境调度,微任务由 JS 引擎调度,是异步编程的核心基础