JavaScript的宏任务(MacroTask)和微任务(MicroTask)

article/2025/7/22 0:51:03

JavaScript 的 宏任务(MacroTask)微任务(MicroTask) 是事件循环机制中的核心概念,它们决定了异步代码的执行顺序。以下是详细说明:


一、核心概念

1. 宏任务(MacroTask)
  • 定义:由宿主环境(浏览器或 Node.js)发起的异步任务,每次事件循环中只执行一个宏任务。
  • 常见类型
  • setTimeout / setInterval
  • I/O 操作(如文件读写、网络请求)
  • UI 渲染(浏览器中的重绘、回流)
  • 用户交互事件(如 clickload
  • 整体脚本代码(<script> 标签内的同步代码)
  • requestAnimationFrame(浏览器动画)
  • 特点
    • 每次事件循环执行一个宏任务。
    • 执行完毕后会处理所有微任务,再进入下一轮事件循环。
2. 微任务(MicroTask)
  • 定义:高优先级的异步任务,在当前宏任务执行完毕后立即执行,且在下一个宏任务开始前清空微任务队列。
  • 常见类型
  • Promise.then / catch / finally
  • MutationObserver(监听 DOM 变化)
  • queueMicrotask(显式添加微任务)
  • process.nextTick(Node.js 中优先级最高)
  • 特点
    • 执行顺序优先于宏任务。
    • 微任务队列会一次性清空,即使在微任务中添加新的微任务也会立即执行。

二、事件循环执行顺序

JavaScript 的事件循环遵循以下流程:

  1. 执行同步代码(宏任务):
    • 主线程按顺序执行同步代码,遇到异步任务(如 setTimeoutPromise)时将其放入对应队列。
  2. 执行所有微任务
    • 当前宏任务执行完毕后,立即清空微任务队列。微任务队列中的任务会依次执行,即使在微任务中添加新的微任务也会继续执行。
  3. 渲染更新(浏览器环境):
    • 如果需要,浏览器会进行 UI 渲染。
  4. 执行下一个宏任务
    • 从宏任务队列中取出下一个任务执行,重复上述流程。

三、执行顺序示例

实际上是先执行同步任务,异步任务有宏任务和微任务两种,先将宏任务添加到宏任务队列中,将宏任务里面的微任务添加到微任务队列中。所有同步执行完之后执行异步,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行。之后就一直循环…
在这里插入图片描述

示例 1:基础执行顺序
console.log("Start"); // 同步代码(宏任务)setTimeout(() => {console.log("setTimeout"); // 宏任务
}, 0);Promise.resolve().then(() => {console.log("Promise 1"); // 微任务
}).then(() => {console.log("Promise 2"); // 微任务
});console.log("End"); // 同步代码(宏任务)

输出结果

Start
End
Promise 1
Promise 2
setTimeout

解析

  1. 同步代码 StartEnd 优先执行。
  2. 微任务 Promise 1Promise 2 在当前宏任务结束后立即执行。
  3. 宏任务 setTimeout 在微任务队列清空后执行。
示例 2:微任务嵌套
console.log("Start"); // 同步代码Promise.resolve().then(() => {console.log("Promise 1"); // 微任务Promise.resolve().then(() => {console.log("Promise 2"); // 新增的微任务});
});console.log("End"); // 同步代码

输出结果

Start
End
Promise 1
Promise 2

解析

  • 微任务 Promise 1 执行时,新增的 Promise 2 会被立即加入微任务队列,并在当前轮事件循环中优先执行。
示例 3
setTimeout(function(){console.log('1');
});
new Promise(function(resolve){		    console.log('2');resolve();
}).then(function(){		    console.log('3');
}).then(function(){
console.log('4')
}); 		
console.log('5');
// 2 5 3 4 1

解析

1.遇到setTimout,异步宏任务,放入宏任务队列中
2.遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2
3.而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
4.遇到同步任务console.log(‘5’);输出5;主线程中同步任务执行完
5.从微任务队列中取出任务到主线程中,输出3、 4,微任务队列为空
6.从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空

示例 4
setTimeout(()=>{new Promise(resolve =>{resolve();}).then(()=>{console.log('test');});console.log(4);
});new Promise(resolve => {resolve();console.log(1)
}).then( () => {console.log(3);Promise.resolve().then(() => {console.log('before timeout');}).then(() => {Promise.resolve().then(() => {console.log('also before timeout')})})
})
console.log(2);

解析:

1.遇到setTimeout,异步宏任务,将() => {console.log(4)}放入宏任务队列中;

2.遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出1;

3.而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
4.遇到同步任务console.log(2),输出2;主线程中同步任务执行完
5.从微任务队列中取出任务到主线程中,输出3,此微任务中又有微任务,Promise.resolve().then(微任务a).then(微任务b),将其依次放入微任务队列中;
6.从微任务队列中取出任务a到主线程中,输出 before timeout;
7.从微任务队列中取出任务b到主线程中,任务b又注册了一个微任务c,放入微任务队列中;
8.从微任务队列中取出任务c到主线程中,输出 also before timeout;微任务队列为空
9.从宏任务队列中取出任务到主线程,此任务中注册了一个微任务d,将其放入微任务队列中,接下来遇到输出4,宏任务队列为空
10.从微任务队列中取出任务d到主线程 ,输出test,微任务队列为空

四、关键区别

特性宏任务(MacroTask)微任务(MicroTask)
定义由宿主环境发起的任务由 JavaScript 自身发起的任务
执行顺序每次事件循环执行一个宏任务当前宏任务结束后立即执行所有微任务
常见示例setTimeout, setInterval, UI 渲染Promise.then, queueMicrotask
优先级
应用场景不紧急的任务(如延迟操作、批量渲染)高优先级任务(如 DOM 更新后的回调)

五、实际应用与注意事项

  1. 控制异步代码顺序

    • 利用微任务的高优先级,确保某些代码在当前宏任务结束后立即执行。
    • 示例:使用 Promise.then 替代 setTimeout 控制执行顺序。
  2. 优化性能

    • 将轻量操作(如 DOM 更新)放在微任务中,避免阻塞宏任务。
    • 将耗时操作(如复杂计算)放在宏任务中,避免 UI 卡顿。
  3. 避免微任务嵌套过深

    • 微任务队列清空前会执行所有新添加的微任务,可能导致宏任务被长时间阻塞。
    • 示例:Promise.then 中嵌套多个微任务时需谨慎处理。
  4. setTimeout(fn, 0) 不是立即执行:
    即使延迟时间为 0,setTimeout 仍需等待当前宏任务和所有微任务执行完毕。

  5. 微任务可能阻塞宏任务:

    如果微任务队列中存在大量任务(如递归触发微任务),会导致宏任务被延迟。

六、Node.js 环境中的差异

在 Node.js 中,事件循环阶段与浏览器不同,但微任务优先级依然高于宏任务:

  1. 宏任务阶段
    • setTimeout / setInterval(Timers 阶段)
    • I/O 回调(I/O Callbacks 阶段)
    • setImmediate(Check 阶段)
  2. 微任务
    • 在每个阶段结束后清空微任务队列。
    • process.nextTick 的优先级高于其他微任务。

七、总结

  • 宏任务:适合不紧急的异步操作,每次事件循环执行一个。

  • 微任务:高优先级任务,在当前宏任务结束后立即执行所有微任务。

  • 设计意义:通过微任务提高响应速度,通过宏任务避免阻塞主线程。


http://www.hkcw.cn/article/PlMOUArqxk.shtml

相关文章

引用第三方自定义组件——微信小程序学习笔记

1. 使用 npm 安装第三方包 1.1 下载安装Node.js 工具 下载地址&#xff1a;Node.js — Download Node.js 1.2 安装 npm 包 在项目空白处右键弹出菜单&#xff0c;选择“在外部终端窗口打开”&#xff0c;打开命令行工具&#xff0c;输入以下指令&#xff1a; 1> 初始化:…

ruoyi-uniapp:实现AI聊天与绘画的小程序

ruoyi-uniapp&#xff1a;实现AI聊天与绘画的小程序 ruoyi-uniapp 基于ruoyi-plus实现AI聊天和绘画功能-小程序 项目地址: https://gitcode.com/gh_mirrors/ru/ruoyi-uniapp 随着科技的快速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术逐渐渗透到我们的日常…

微信小程序-使用vant组件库

文章目录 微信小程序-使用vant组件库概述构建npm构建步骤使用vant注册使用添加事件使用插槽 样式覆盖解除样式隔离使用外部样式类使用CSS变量 微信小程序-使用vant组件库 概述 Vant Weapp 是有赞前端团队开源的小程序 UI 组件库&#xff0c;基于微信小程序的自定义组件开发&a…

微信小程序地图组件开发:UniApp 集成高德 / 腾讯地图 API 详解

前言&#xff1a;家人们&#xff0c;大家好&#xff01;今天分享一篇文章给大家&#xff01;要是文章对你有帮助&#xff0c;激发了你的灵感&#xff0c; 求个收藏 关注啦&#xff5e;后续还有超多惊喜&#xff0c;别错过&#xff01; 目录 一、引言 二、开发前准备 &#…

新版Onenet物联网平台,微信小程序显示上传信息发送指令。STM32ESP8266实现采集数据并上传

目录 前言 一、Onenet平台配置 1.创建产品 2.配置产品属性 3.创建物模型&#xff08;创建设备&#xff09; 二、ESP8266设备连接 1.获取MQTT连接参数 2.Onenet物理属性上传主题 3.上传数据 三、ESP8266和STM32通信 1.STM32发送数据&#xff0c;8266解析并上传 2.82…

uni-app 高效开发小程序技巧:自动化切换环境变量

一. 前言 在微信小程序开发中&#xff0c;uni-app 作为一个开发利器&#xff0c;方便了广大开发者&#xff0c;越来越多的公司开始使用 uni-app 进行开发&#xff0c;尤其是在开发小程序的时候&#xff0c;今天给大家分享一个使用 uni-app 高效开发小程序的技巧&#xff0c;如…

基于微信小程序的旅游攻略分享与互动平台设计与实现

目录 一. &#x1f981; 前言二. &#x1f981; 开源代码与组件使用情况说明三. &#x1f981; 核心功能3.1 游客端功能3.1.1 景点信息查询功能3.1.2 旅游路线推荐功能3.1.3 景点打卡功能3.1.4 评论与互动功能3.1.5 门票预订功能3.1.6 当地美食推荐功能3.1.7 个人中心 3.2 管理…

uni-app 发行到微信小程序,主包过大解决方案

目录 1.静态资源通过cdn引入 2.移除无依赖组件 3.将非核心页面移入subPackages中 正常uni-app项目发行到微信小程序,发现包过大,基本已经没法从代码层面修改内容了,今天这里介绍一些,不用大批量修改源码的情况下,减少包大小的方式 官方默认这包不能超过2M 分包不能超过30M …

微信小程序富文本解析组件wxParse实践指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;微信小程序wxParse组件是一款用于解析和渲染富文本内容的工具&#xff0c;它扩展了小程序对HTML内容的支持&#xff0c;加入了CSS样式和图片懒加载等特性。开发者可以利用这个组件将HTML文本转换为WXML结构&…

微信小程序wx.getlocation接口申请教程

wx.getLocation(Object object) 功能描述&#xff1a; 获取当前的地理位置、速度。当用户离开小程序后&#xff0c;此接口无法调用。开启高精度定位&#xff0c;接口耗时会增加&#xff0c;可指定 highAccuracyExpireTime 作为超时时间。地图相关使用的坐标格式应为 gcj02。 …

【一文读懂】uniapp微信小程序获取手机号-手机号快速验证组件(全流程)

微信小程序获取手机号&#xff0c;要分几步&#xff0c;再次做个记录&#xff0c;希望耐心看完。 1. 第一步&#xff0c;先获取code&#xff0c;并不是登入的那个code&#xff0c; 2. 第二步&#xff0c;根据小程序的appid获取access_token凭证&#xff0c; 3. 第三步&#xf…

微信小程序实现微信授权登录的完整流程

1. 概述 微信授权登录是小程序用户登录的常见方式&#xff0c;利用微信提供的 wx.login 和 wx.getUserProfile 方法&#xff0c;获取用户的基本信息和唯一标识 openid 及 session_key。结合后端存储及业务逻辑&#xff0c;可以实现用户的身份管理。 2. 流程图 用户授权登录的…

微信小程序页面制作——婚礼邀请函(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

经济学泰斗菲舍尔逝世:培育伯南克、德拉吉的央行界“一代宗师” 全球金融体系的“救火队长”

当地时间6月1日,以色列央行宣布世界著名经济学家、以色列央行前行长及美联储前副主席斯坦利菲舍尔于5月31日逝世,享年81岁。菲舍尔拥有美国和以色列双重国籍,其职业生涯横跨学术界、国际金融机构与中央银行,对全球经济政策产生了深远影响。他曾担任以色列银行行长,并出任美…

高动态范围射频收发器如何解决关键性任务通信的阻塞挑战

摘要 由于频谱有限&#xff0c;商用/专用蜂窝网络的使用越来越多&#xff0c;无线电平台开发面临着更复杂的干扰场景。本文将讨论高动态范围射频收发器 ADRV9002 软件定义无线电(SDR)如何应对关键性任务通信无线电和其他高动态要求无线应用的阻塞挑战。 引言 关键性任务通信…

达科欢迎樊振东加入球队 德甲新星闪耀

#达科欢迎樊振东加入球队# 德甲联赛萨尔布吕肯乒乓球甲级俱乐部 宣布樊振东 加盟球队,效力于该队的达科-约奇克在社交媒体欢迎樊振东加入球队。#樊振东加盟德甲联赛#责任编辑:zx0001

北京今天最高气温达31℃!假期结束防暑降温模式正式开启 北风加大注意防护

据北京市气象局消息,6月2日08时,南郊观象台气温为21.4℃。预计今天白天最高气温将达到31℃左右,外出时请注意遮阳防晒并勤补水。受冷空气影响,今天白天北风自西向东逐渐加大,阵风可达6、7级,请注意防风,防范高空坠物。早晨天气晴间多云,有轻雾,偏北风1、2级,气温在17…

乌为何剑走偏锋突袭俄战略轰炸机 FPV无人机木马立奇功

以色列有“BP机炸弹”,乌克兰有“FPV无人机木马”,这似乎在逼迫普京使用战术核武器。6月1日,据媒体报道,经过18个月的策划,乌克兰实施了代号为“蜘蛛网”的行动,摧毁了41架俄罗斯战略轰炸机。乌克兰安全局发言人表示,此次行动由泽连斯基亲自指挥,乌安全局长马柳克负责具…

2025三掌柜赠书活动第十九期 DeepSeek图书:全年龄段的智慧之选,一本书开启知识之旅

目录 Part.0 前言 Part.1 职场人的AI效率革命&#xff1a;解锁DeepSeek多元应用&#xff0c;精准解决高频痛点&#xff01; Part.2 企业家的必修课&#xff1a;用AI重构商业模式&#xff0c;打造下一个独角兽&#xff01; Part.3 学术党的救命稻草&#xff1a;选题到答辩全辅…

Spring Boot + MyBatis 实现的简单用户管理项目的完整目录结构示例

&#x1f4c1; 示例项目结构&#xff08;基于 Maven&#xff09; user-management/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/example/usermanagement/ │ │ │ ├── controller/ │ │ │ │ └── UserC…