news 2026/4/16 12:39:04

宏任务与微任务:前端面试必考执行顺序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
宏任务与微任务:前端面试必考执行顺序

宏任务 / 微任务执行顺序(经典面试题详解)

你关注的宏任务、微任务执行顺序是前端面试的核心考点,尤其围绕setTimeoutPromise.thenasync/await的执行逻辑,我会从概念定义、执行机制到经典例题,帮你彻底理清。

一、先明确:宏任务(Macrotask)vs 微任务(Microtask)

1. 宏任务(Macrotask)

宏任务是浏览器 / Node.js 执行的大型异步任务单元,每次执行一个宏任务,执行完成后会先清空所有微任务,再进入下一个宏任务。

常见宏任务类型:

  • setTimeoutsetInterval(定时器异步任务)
  • setImmediate(Node.js 环境)
  • requestAnimationFrame(浏览器环境)
  • 脚本整体代码(<script>标签中的同步代码,属于第一个宏任务)
  • I/O 操作(文件读取、网络请求等异步操作)

2. 微任务(Microtask)

微任务是优先级更高的小型异步任务,会在当前宏任务执行完毕后、下一个宏任务执行前,被批量清空(按顺序执行所有微任务)。

常见微任务类型:

  • Promise.then()/Promise.catch()/Promise.finally()(Promise 状态改变后的回调)
  • async/awaitawait后面的代码(本质是 Promise.then 的语法糖,属于微任务)
  • process.nextTick(Node.js 环境,优先级高于普通微任务)
  • MutationObserver(浏览器环境,监听 DOM 变化的回调)

二、核心执行机制(事件循环 Event Loop 关键规则)

  1. 先执行当前宏任务中的同步代码,按代码书写顺序依次执行;
  2. 同步代码执行过程中,遇到异步任务会分别归类到「宏任务队列」或「微任务队列」;
  3. 当当前宏任务的同步代码执行完毕后,立即清空微任务队列:按微任务添加顺序,依次执行所有微任务(若微任务执行过程中产生新的微任务,仍会加入当前微任务队列,一并清空);
  4. 微任务队列清空后,执行一次 UI 渲染(浏览器环境)/ 收尾操作(Node.js 环境);
  5. 从宏任务队列中取出下一个优先级最高的宏任务执行,重复步骤 1-4,形成事件循环。

一句话总结:宏任务按队列排队执行,每个宏任务执行后,必先清空微任务队列,再执行下一个宏任务(微任务优先级 > 宏任务)

三、关键知识点:async/await 的执行逻辑

async/await是 Promise 的语法糖,其执行顺序需重点掌握:

  1. async修饰的函数,会返回一个 Promise 实例,函数内部同步代码正常执行;
  2. await关键字后面的表达式,会先同步执行(获取表达式结果);
  3. await会暂停当前函数的执行,将await后面的代码(即 “后续逻辑”)加入微任务队列(而非同步执行);
  4. await后面的 Promise 状态变为fulfilled后,微任务队列中的 “后续逻辑” 才会执行。

示例验证:

async function testAsync() { console.log("1. await 前的同步代码"); await Promise.resolve("await 结果"); // await 后面的表达式同步执行 console.log("2. await 后的代码(微任务)"); } console.log("0. 全局同步代码"); testAsync(); console.log("3. 全局同步代码后续"); // 执行结果顺序:0 → 1 → 3 → 2 // 解析: // 1. 先执行全局同步代码:输出 0; // 2. 调用 testAsync,执行内部同步代码:输出 1; // 3. 执行 await 后面的 Promise.resolve(同步),然后将 console.log("2...") 加入微任务队列; // 4. 退出 testAsync,继续执行全局同步代码:输出 3; // 5. 当前宏任务(全局脚本)同步代码执行完毕,清空微任务队列:输出 2。

四、经典面试题解析(覆盖 setTimeout/Promise/async/await)

面试题 1:基础版(setTimeout + Promise.then)

console.log("1. 全局同步代码"); setTimeout(() => { console.log("4. setTimeout 宏任务"); }, 0); Promise.resolve() .then(() => { console.log("3. Promise.then 微任务"); }); console.log("2. 全局同步代码后续");
执行结果顺序
1. 全局同步代码 2. 全局同步代码后续 3. Promise.then 微任务 4. setTimeout 宏任务
解析
  1. 执行当前宏任务(全局脚本)的同步代码:先输出 1,再输出 2;
  2. 同步执行过程中:
    • setTimeout回调被加入「宏任务队列」;
    • Promise.resolve()立即变为 fulfilled 状态,then回调被加入「微任务队列」;
  3. 全局同步代码执行完毕,清空微任务队列:输出 3;
  4. 微任务队列清空,取出宏任务队列中的setTimeout回调执行:输出 4。

面试题 2:进阶版(setTimeout + Promise + async/await)

console.log("1. 全局同步代码"); setTimeout(() => { console.log("6. setTimeout 宏任务1"); Promise.resolve().then(() => { console.log("7. setTimeout 内部的微任务"); }); }, 0); setTimeout(() => { console.log("8. setTimeout 宏任务2"); }, 0); async function asyncFunc() { console.log("2. async 内部同步代码"); await Promise.resolve(); console.log("5. await 后的微任务"); } asyncFunc(); Promise.resolve() .then(() => { console.log("4. 全局 Promise 微任务"); }); console.log("3. 全局同步代码后续");
执行结果顺序
1. 全局同步代码 2. async 内部同步代码 3. 全局同步代码后续 4. 全局 Promise 微任务 5. await 后的微任务 6. setTimeout 宏任务1 7. setTimeout 内部的微任务 8. setTimeout 宏任务2
解析
  1. 执行全局宏任务的同步代码:
    • 输出 1;
    • 调用asyncFunc,执行内部同步代码,输出 2;
    • await Promise.resolve()同步执行后,将console.log("5...")加入微任务队列;
    • Promise.resolve().then(...)console.log("4...")加入微任务队列;
    • 输出 3;
  2. 全局同步代码执行完毕,清空微任务队列(按添加顺序执行):
    • 先执行全局 Promise 的微任务,输出 4;
    • 再执行 async/await 的微任务,输出 5;
  3. 微任务队列清空,执行下一个宏任务(第一个 setTimeout):
    • 输出 6;
    • 其内部的Promise.then回调加入微任务队列,立即清空该微任务队列,输出 7;
  4. 第一个 setTimeout 宏任务执行完毕,执行下一个宏任务(第二个 setTimeout):输出 8。

面试题 3:高阶版(含微任务嵌套 + 宏任务优先级)

console.log("1. 全局同步代码"); async function async1() { await async2(); console.log("6. async1 await 后代码"); } async function async2() { console.log("2. async2 同步代码"); return Promise.resolve().then(() => { console.log("4. async2 返回的 Promise 微任务"); }); } async1(); Promise.resolve() .then(() => { console.log("5. 全局 Promise 微任务"); }); setTimeout(() => { console.log("7. setTimeout 宏任务"); Promise.resolve().then(() => { console.log("8. setTimeout 内部微任务"); }); }, 0); console.log("3. 全局同步代码后续");
执行结果顺序
1. 全局同步代码 2. async2 同步代码 3. 全局同步代码后续 4. async2 返回的 Promise 微任务 5. 全局 Promise 微任务 6. async1 await 后代码 7. setTimeout 宏任务 8. setTimeout 内部微任务
解析
  1. 执行全局同步代码:输出 1 → 调用async1→ 执行await async2(),先调用async2
  2. 执行async2同步代码:输出 2 →return Promise.resolve().then(...),该then回调加入微任务队列;
  3. async2执行完毕,await等待其返回的 Promise 完成,将console.log("6...")加入微任务队列(需等async2的 Promise 微任务执行完才会触发);
  4. 继续执行全局同步代码:输出 3 → 全局Promise.then回调加入微任务队列;
  5. 全局同步代码执行完毕,清空微任务队列:
    • 先执行async2内部的 Promise 微任务:输出 4;
    • 再执行全局 Promise 微任务:输出 5;
    • 最后执行async1await 后的微任务:输出 6;
  6. 微任务队列清空,执行setTimeout宏任务:输出 7 → 其内部 Promise 微任务立即执行,输出 8。

五、总结(核心考点提炼)

  1. 队列优先级:微任务队列 > 宏任务队列(当前宏任务执行后,必先清空微任务);
  2. 微任务包含Promise.then/catch/finallyasync/await后续代码;
  3. 宏任务包含setTimeout/setInterval、全局脚本、I/O 操作;
  4. async/await 关键await后面的表达式同步执行,后续代码进入微任务队列;
  5. 执行流程口诀:同步代码先执行 → 微任务队列全清空 → 宏任务队列取一个 → 重复循环。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:59:43

【课程设计/毕业设计】基于springboot的幼儿园管理系统的设计与实现幼儿信息管理、班级信息管理、工作日志管理【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/16 6:04:22

1991-2025年地市级年度科学家数量统计数据

数据简介 科学家作为科技创新的核心载体与区域发展的关键生产要素&#xff0c;其在地级市层面的年度分布特征与动态演化&#xff0c;直接关系到区域创新生态构建、产业转型升级及高质量发展全局&#xff0c;是解析创新资源空间配置效率、评估人才政策实施效果的核心基础数据。…

作者头像 李华
网站建设 2026/4/16 6:04:21

【机械】螺旋千斤顶的标准机械分析Matlab实现

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码获取及仿…

作者头像 李华
网站建设 2026/4/16 5:59:30

从“文件即接口”到“我的一生.OFD”

前言去年我参加了2024上海智慧档案高峰论坛&#xff0c;在这个论坛上&#xff0c;OFD标准的责任编辑、中国电子标准院信息化研究室陈亚军主任向所有参会者公开分享了“文件即接口”的理念。我认同这个理念&#xff0c;并从这个理念出发&#xff0c;结合医院信息化行业特点&…

作者头像 李华
网站建设 2026/4/16 6:03:06

为什么Java/Python程序无需关心内存释放?揭秘垃圾回收(GC)的核心概念

在Java的编程世界里&#xff0c;开发者既无需也无法像C/C那样手动调用malloc/free来管理内存的分配与回收&#xff0c;这一核心任务完全由Java虚拟机在幕后自动完成。这种自动化设计极大地简化了编码&#xff0c;将开发者从繁琐且极易出错的内存管理中解放出来。然而&#xff0…

作者头像 李华