JS事件循环、宏任务与微任务

news2024/12/24 2:12:24

在JavaScript中,事件循环(Event Loop)是处理异步操作的核心机制。它负责执行代码,处理事件,并在适当的时候调度回调。为了更好地理解JavaScript的执行模型,我们需要深入探讨事件循环、宏任务(MacroTask)和微任务(MicroTask)之间的关系和运作方式。

一、事件循环

事件循环是JavaScript的运行时环境(如浏览器和Node.js)提供的一种机制,用于处理异步操作。它将JavaScript代码分为同步任务和异步任务,并确保在适当的时机执行这些任务。

二、宏任务与微任务

在事件循环中,异步任务被分为两类:宏任务(MacroTask)和微任务(MicroTask)。

1. 宏任务(MacroTask)

宏任务包括整体代码script、setTimeout、setInterval、setImmediate(Node.js环境)、I/O、UI渲染等。每个宏任务都会触发一个新的事件循环。

2. 微任务(MicroTask)

微任务包括Promise的then和catch方法、process.nextTick(Node.js环境)和MutationObserver(浏览器环境)等。微任务在执行完一个宏任务后,会立即在当前事件循环中执行。

三、事件循环的执行流程

事件循环的执行流程可以概括为以下几个步骤:

  1. 执行栈为空时:如果执行栈为空,事件循环会检查微任务队列是否有任务。如果有,则依次执行微任务,直到微任务队列为空。

  2. 执行微任务:执行完微任务后,事件循环会取出宏任务队列中的一个宏任务来执行。

  3. 执行宏任务:执行宏任务的过程中,如果遇到异步任务(如setTimeout、Promise等),这些任务会被放入对应的队列中等待执行。

  4. 循环执行:执行完一个宏任务后,事件循环会回到第1步,继续检查微任务队列并执行微任务。这个过程会不断重复,形成一个循环。

下面是一个简化的JavaScript事件循环的代码示例,该示例展示了事件循环如何处理宏任务(如setTimeout)和微任务(如Promise

// 宏任务队列
const macroTaskQueue = [];
// 微任务队列
const microTaskQueue = [];

// 当前正在执行的宏任务
let currentMacroTask = null;

// 模拟事件循环
function eventLoop() {
  // 执行当前宏任务
  if (currentMacroTask) {
    currentMacroTask();
    currentMacroTask = null;
  }

  // 执行所有微任务
  while (microTaskQueue.length > 0) {
    const microTask = microTaskQueue.shift();
    microTask();
  }

  // 检查是否有新的宏任务加入队列
  if (macroTaskQueue.length > 0) {
    // 获取下一个宏任务
    currentMacroTask = macroTaskQueue.shift();
    // 开始新的事件循环迭代
    eventLoop();
  } else {
    // 如果没有宏任务,则事件循环结束
    console.log('事件循环结束');
  }
}

// 添加宏任务到队列
function scheduleMacroTask(task) {
  macroTaskQueue.push(task);
  // 如果当前没有宏任务在执行,则开始事件循环
  if (!currentMacroTask) {
    eventLoop();
  }
}

// 添加微任务到队列
function scheduleMicroTask(task) {
  microTaskQueue.push(task);
}

// 示例:使用setTimeout添加宏任务
scheduleMacroTask(() => {
  console.log('宏任务1');
  // 添加另一个宏任务
  scheduleMacroTask(() => {
    console.log('宏任务2');
  });
  // 添加微任务
  Promise.resolve().then(() => {
    console.log('微任务1');
  });
});

// 示例:使用Promise添加微任务
Promise.resolve().then(() => {
  console.log('微任务2');
});

// 开始事件循环
eventLoop();

四、宏任务与微任务的区别

宏任务和微任务的主要区别在于它们的执行时机和优先级。宏任务在每个事件循环开始时被执行,而微任务则在执行完一个宏任务后立即执行。因此,微任务的优先级高于宏任务。

这种设计使得微任务可以在不阻塞其他宏任务的情况下快速执行,从而提高了程序的响应速度和性能。

五、Promise与事件循环

Promise是JavaScript中用于处理异步操作的一种对象。它的then和catch方法返回的是一个新的Promise对象,这个对象会被放入微任务队列中等待执行。这意味着,当我们使用Promise进行异步操作时,相关的回调函数会在当前事件循环的微任务阶段被执行。

六、总结

在实际开发中,合理利用Promise等微任务机制,可以提高程序的性能和响应速度。同时,了解事件循环的工作原理也有助于我们避免一些常见的异步编程陷阱和错误。随着JavaScript的不断发展,事件循环和异步编程模型也在不断完善。同时,Web Workers、Service Workers等技术的普及,我们也可以在多线程环境中利用事件循环和异步编程模型来提高程序的并发性能和用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1633580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式与一致性协议之Raft算法(二)

Raft算法 什么是任期 我们知道,议会选举中的领导者是有任期的,当领导者任命到期后,需要重新再次选举。Raft算法中的领导者也是有任期,每个任期由单调递增的数字(任期编号)标识。比如,节点A的任期编号是1。任期编号会…

基于Docker + Locust的数据持久化性能测试系统

前几天给大家分享了如何使用Locust进行性能测试,但是在实际使用中会发现存在压测的结果无法保存的问题,比如在分布式部署情况下进行压测,每轮压测完成需要释放资源删除容器重新部署后,这段时间的压测结果就都丢失了,如…

Nacos 安全零信任实践

作者:柳遵飞 Nacos 作为配置中心经常存储一些敏感信息,但是由于误用导致安全风险,最常见的主要是以下两个问题: 1)Nacos 暴露公网可以吗?不可以,因为 Nacos 定位是注册配置中心,是…

【STM32+HAL】SDIO模式读写SD卡

一、准备工作 有关CUBEMX的初始化配置,参见我的另一篇blog:【STM32HAL】CUBEMX初始化配置 二、所用工具 1、芯片: STM32F407ZGT6 2、IDE: MDK-Keil软件 3、库文件:STM32F4xxHAL库 三、实现功能 实现用DMA读写SD卡内…

Hadoop3:集群搭建及常用命令与shell脚本整理(入门篇,从零开始搭建)

一、集群环境说明 1、用VMware安装3台Centos7.9虚拟机 2、虚拟机配置:2C,2G内存,50G存储 3、集群架构 从表格中,可以看出,Hadoop集群,主要有2部分,一个是HDFS服务,一个是YARN服务 …

CSS中的层叠上下文

HTML 文档中的三维概念 平时我们从设备终端看到的 HTML 文档都是一个平面的,事实上 HTML 文档中的元素却是存在于三个维度中。除了大家熟悉的平面画布中的 x 轴和 y 轴,还有控制第三维度的 z 轴。 其中 x 轴通常用来表示水平位置,y 轴来表示…

力扣刷题Day2

题目链接: 24. 两两交换链表中的节点 - 力扣(LeetCode) 效果: 解题思路: 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 注意不可以只是单纯的改变节点内部的值,而…

面试:MYSQL(SQL优化、MYSQL事务)

目录 一、SQL优化 1、如何定位慢查询 (1)方案一:开源工具 (2)方案二:慢日志查询 2、定位到慢查询时,如何优化 3、什么是索引 (1)底层结构 4、聚簇索引&#xff0…

linux学习:线程安全(信号量+互斥锁读写锁+条件变量+可重入函数)

目录 信号量 有名信号量 步骤 api 创建、打开一个POSIX有名信号量 对 POSIX 有名信号量进行 P、V 操作 关闭、删除 POSIX 有名信号量 例子 无名信号量 步骤 api 初始化、销毁 POSIX 无名信号量 互斥锁读写锁 例子 两条线程 使用互斥锁来互斥地访问标准输出 在加锁…

UE Snap03 启动参数设置

UE Snap03 启动参数设置 UE打包后传入自定义参数及解析。 void UGameInstance::StartGameInstance() {Super::StartGameInstance();UE_LOG(LogTemp, Warning, TEXT("--StartGameInstance--"));FString param;FParse::Value(FCommandLine::Get(), TEXT("-UserN…

# 谷歌 Chrome 浏览器无法安装插件的解决方法

谷歌 Chrome 浏览器无法安装插件的解决方法 运用开发模式安装 安装步骤: 1、 将 XX.crx 插件的扩展名改成 .zip 或者 .rar 并解压到文件夹 XX 目录。 1)如:下载的 前端框架 vue.js 插件 nhdogjmejiglipccpnnnanhbledajbpd-6.6.1-Crx4Chro…

Isaac Sim 2 (学习笔记4.26)

今天一整天都要开会,闲的无聊,把这周学的东西简单整理下。纯英文文档想不起来东西的时候总是找不到位置...持续更新一整天 1.将块与块连接起来 尝试连接块与块的时候发现只能是cube、mesh连接,如果是一整个的包括坐标系、材质包等等&#xf…

阿里云服务器购买和设置

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:服务器❤️感谢大家点赞👍收藏⭐评论✍️ 目录 1、搜索阿里云网址: 2、点击产品,选择云服务器ECS 3、选择立即购买 4、选…

C# Web控件与数据感应之 Control 类

目录 关于数据感应 Control 类 范例运行环境 simpleDataListEx方法 设计 实现 调用示例 数据源 调用 小结 关于数据感应 数据感应也即数据捆绑,是一种动态的,Web控件与数据源之间的交互,诸如 ListControl 类类型控件,在…

uni-app - 使用地图功能打包安卓apk的完美流程以及重要的注意事项(带您一次打包成功)

在移动应用开发中,地图功能是一个非常常见且实用的功能,可以帮助用户快速定位并浏览周边信息。而在uni-app开发中,使用地图功能也是一项必备技能。本文将介绍uni-app使用地图功能打包安卓apk的注意事项,帮助开发者顺利完成地图功能…

万兆以太网MAC设计(12)万兆UDP协议栈上板与主机网卡通信

文章目录 一、设置IP以及MAC二、上板效果2.1、板卡与主机数据回环测试2.2、板卡满带宽发送数据 一、设置IP以及MAC 顶层模块设置源MAC地址 module XC7Z100_Top#(parameter P_SRC_MAC 48h01_02_03_04_05_06,parameter P_DST_MAC 48hff_ff_ff_ff_ff_ff )(input …

excel图表如何忽略空值呢?

在excel柱形图和折线图中有多余的空值,如何不把空值当成0值处理,可以达到第二个图的效果? 添加图片注释,不超过 140 字(可选) 用的excel2019已经是自动将这些空值忽略了,在低版本上,是会将空值…

2024年想创业做电商,视频号小店绝对是最明智的选择!

大家好,我是电商糖果 在电商行业摸爬滚打了七年时间了,做过天猫,京东,闲鱼。 目前在做的项目只有两个,一个是抖音小店,已经做了四年多了。 另一个就是视频号小店,现在做了有一年多了。 视频…

力扣HOT100 - 79. 单词搜索

解题思路&#xff1a; 深度优先搜索&#xff08;DFS&#xff09; 剪枝。 class Solution {public boolean exist(char[][] board, String word) {char[] words word.toCharArray();for(int i 0; i < board.length; i) {for(int j 0; j < board[0].length; j) {if (df…

docker compose安装redis

一、安装准备 在docker hub查看redis镜像版本。查看地址如下&#xff1a; Dockerhttps://hub-stage.docker.com/_/redis/tags 二、拉取docker镜像 我这里用redis:6.2.14版本&#xff0c;先拉取镜像。命令如下&#xff1a; docker pull redis:6.2.14 查看刚刚下载的镜像&am…