javaScript 中的宏任务、微任务

宏任务:

是指,需要排队等待 JavaScript 引擎空闲时才能执行的任务,

常见的宏任务包括 setTimeout、setInterval、setImmediate(Node.js 独有)、requestAnimationFrame、I/O 操作、XMLHttpRequest、DOM事件等

微任务:

是指,在当前任务执行结束后,立即执行的任务,它可以看作是在当前任务的“尾巴”添加的任务,

常见的微任务包括 Promise回调函数、process.nextTick、Object.observe(已废弃)、MutationObserver

说一下

JavaScript引擎,会先执行当前任务中的所有微任务,然后再执行宏任务队列中的第一个任务,这个过程会不断重复,直到宏任务队列中的任务被全部执行完毕。

宏任务、微任务都属于异步任务,

宏任务包括 setTimeout、setInterval、I/O 等操作,

微任务包括 promise的then、resolve、reject 等

首先执行同步代码,遇到异步任务,如果是宏任务就放入宏任务队列,微任务就放到微任务队列,

当同步代码执行完毕,就会执行微任务队列,直到微任务队列清空,

然后从宏任务对列调用宏任务到主线程执行,就这样不断循环,直到所有任务执行完毕




JavaScript之所以要区分微任务、宏任务,是因为,微任务和宏任务的执行顺序不同,这对Web开发中一些异步操作的实现有重要的影响

在JavaScript中,微任务会优先于宏任务执行,
这意味着,在当前任务执行结束后,所有微任务都会被立即执行,而宏任务只有在所有微任务执行完毕后才会执行,
这种执行顺序保证了微任务的优先级,可以避免一些问题的出现。

1、
比如,处理 Promise对象时可能会出现的竞态条件,

举个例子,当我们使用Promise对象时,它会返回一个Promise实例并将回调函数放入微任务队列中,

当 Promise的状态发生改变时,它会立即执行微任务队列中的回调函数,而不是等待当前任务结束后再执行,

这种特性可以保证 Promise回调函数的执行顺序,避免出现竞态条件,从而使代码更加可靠。

补充(举例解释一下):
假设,有两个Promise对象P1、P2,
它们的状态都发生了改变,但是P1的回调函数在微任务队列中先于P2的回调函数执行,
这种情况下,即使P2的状态改变发生在P1之前,P2的回调函数也会等待P1的回调函数执行完毕后再执行,
这样可以避免多个回调函数同时执行而产生的竞态条件。

如果当前任务执行一半了,Promise状态发生改变了,会停下当前任务去执行微任务队列中Promise的回调函数吗??????
不会的,
即使当前任务执行了一半,如果Promise状态发生改变,也会立即执行微任务队列中的回调函数,
但是不会停下当前任务的执行。当前任务的执行会继续完成,然后才会回到微任务队列中执行其他的回调函数,
因此,即使Promise状态发生改变,也不会直接打断当前任务的执行。

2、
另一方面,宏任务的执行是在当前任务结束后才会执行的,这意味着,可以将一些耗时的操作放入宏任务队列中,从而避免阻塞当前任务的执行,

比如,我们可以将一些需要等待一段时间才能执行的代码放入 setTimeout 的回调函数中,

这样可以使页面在执行这些代码的同时仍然保持响应,提高用户体验。

因此,JavaScript 之所以要区分微任务和宏任务,是为了保证异步操作的正确性和性能。


JS中微任务和宏任务执行顺序

1、首先执行当前代码(同步任务),直到遇到第一个宏任务或微任务,

2、如果遇到微任务,则将它添加到微任务队列中,继续执行同步任务,

3、如果遇到宏任务,则将它添加到宏任务队列中,继续执行同步任务,

4、当前任务执行完毕后,JavaScript引擎会先执行所有微任务队列中的任务,直到微任务队列为空,

5、然后执行宏任务队列中的第一个任务,直到宏任务队列为空,

重复步骤4、步骤5,直到所有任务都被执行完毕。

需要注意的是,微任务比宏任务优先级要高,因此在同一个任务中,如果既有微任务又有宏任务,那么微任务会先执行完毕,

而在不同的任务中,宏任务的执行优先级要高于微任务,因此在一个宏任务执行完毕后,它才会执行下一个宏任务和微任务队列中的任。

  • 举个例子,

假设当前代码中有一个 setTimeout(宏任务) 和一个 Promise(微任务),它们分别对应一个宏任务和一个微任务。那么执行顺序如下:

1、执行当前代码,将 setTimeout 和 Promise 添加到宏任务和微任务队列中,

2、当前任务执行完毕,JavaScript引擎,先执行微任务队列中的 Promise回调函数,

3、微任务队列为空后,再执行宏任务队列中的 setTimeout回调函数。

需要注意的是:在一些特殊情况下,微任务和宏任务的执行顺序可能会发生变化,比如在使用 MutationObserver 监听 DOM 变化时,
它会被视为一个微任务,但是它的执行顺序可能会比其他微任务更靠后。因此,需要根据具体情况来理解和处理微任务和宏任务的执行顺序。


看下面几个案例

1、微任务:Promise回调函数,宏任务:setTimeout回调函数

console.log('start')setTimeout(() => console.log('setTimeout'), 0)Promise.resolve().then(() => console.log('Promise'))console.log('end')// start、end、Promise、setTimeout

首先输出 start,然后通过 setTimeout 方法注册了一个回调函数,它会被添加到宏任务队列中,

接着创建了一个 Promise实例,并且通过 then方法注册了一个回调函数,在 Promise对象的状态改变时会执行这个回调函数,

接着输出 end,

因为 Promise回调函数是微任务,所以它会被添加到微任务队列中,等待执行,

等到主线程的同步任务执行完毕后,JavaScript引擎会先执行微任务队列中的任务,输出 Promise,然后执行宏任务队列中的任务,输出 setTimeout。


2、微任务:process.nextTick回调函数,宏任务setImmediate 回调函数

console.log('start')setImmediate(() => console.log('setImmediate'))process.nextTick(() => console.log('process.nextTick'))console.log('end')// start、end、process.nextTick、setImmediate

在Node.js环境中,process.nextTick回调函数是排在微任务队列最前面的,优先级比 Promise回调函数还要高,
而 setImmediate回调函数是排在宏任务队列最后面的。

所以,以上代码会先输出 start,然后输出 end,
等到主线程的同步任务执行完毕后,JavaScript引擎会先执行微任务队列中的任务,输出 process.nextTick,然后执行宏任务队列中的任务,输出 setImmediate。


3、微任务:Promise回调函数,宏任务:requestAnimationFrame回调函数

console.log('start')requestAnimationFrame(() => console.log('requestAnimationFrame'))Promise.resolve().then(() => console.log('Promise'))console.log('end')// start、end、Promise、requestAnimationFrame

首先输出 start,然后通过 requestAnimationFrame方法注册了一个回调函数,它会被添加到宏任务队列中,

接着创建了一个 Promise实例,并且通过 then方法注册了一个回调函数,在 Promise对象的状态改变时会执行这个回调函数,

接着输出 end,

因为 Promise回调函数是微任务,所以它会被添加到微任务队列中,等待执行,

等到主线程的同步任务执行完毕后,JavaScript引擎会先执行微任务队列中的任务,输出 Promise,然后执行宏任务队列中的任务,输出 requestAnimationFrame。


4、微任务:Promise回调函数,宏任务:XMLHttpRequest

console.log('start')// 创建 XMLHttpRequest对象并设置 onload回调函数。这个函数会在 HTTP请求成功完成后被调用。
const xhr = new XMLHttpRequest()
xhr.onload = () => console.log('XMLHttpRequest')
xhr.open('GET', 'someurl')
xhr.send()Promise.resolve().then(() => console.log('Promise'))console.log('end')// start、end、Promise、XMLHttpRequest

首先输出 start,然后创建了一个 XMLHttpRequest对象,并且通过 open方法 和 send方法发送了一个 GET请求,

接着通过 onload方法注册了一个回调函数,在请求成功后会执行这个回调函数,

接着创建了一个 Promise实例,并且通过 then方法注册了一个回调函数,在 Promise对象的状态改变时会执行这个回调函数,

接着输出 end,

因为 Promise回调函数是微任务,所以它会被添加到微任务队列中,等待执行,

等到主线程的同步任务执行完毕后,JavaScript引擎会先执行微任务队列中的任务,输出 Promise,

然后等待 XMLHttpRequest对象的回调函数执行,

当请求成功后,JavaScript引擎会执行宏任务队列中的任务,输出 XMLHttpRequest。

  • 请注意,这个执行顺序取决于网络请求的速度和主线程的同步任务执行速度。如果网络请求速度较慢,或者主线程的同步任务执行速度较慢,那么 Promise 和 XMLHttpRequest 的执行顺序可能会稍有不同。

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

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

相关文章

优思学院|新版ISO9001:2015质量体系的优势(一)高阶结构

在全球商业环境中,不断提高产品和服务的质量至关重要。因此,国际标准组织(ISO)于2015年发布了更新的ISO 9001标准,即ISO 9001:2015质量体系标准。这一更新旨在适应不断变化的商业需求和挑战,为组织提供更强…

Idea 编译SpringBoot项目Kotlin报错/Idea重新编译

原因应该是一次性修改了大量的文件, SpringBoot项目启动Kotlin报错, Build Project也是同样的结果, 报错如下 Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.9.0, expected version is 1.1.13. Build-&…

多svn仓库一键更新脚本分享

之前分享过多git仓库一键更新脚本,本期就分享下svn仓库的一键更新脚本 1、首先需要设置svn为可执行命令行 打开SVN安装程序,选择modify,然后点击 command client tools,安装命令行工具 2、update脚本 echo 开始更新SVN目录&…

qt+opengl 着色器VAO、VBO、EBO(四)

文章目录 一、顶点着色器和片段着色器代码分析1. 着色器12. 顶点着色器2 二、使用步骤1. 使用着色器12. 使用着色器23. 在着色器2中使用EBO 三、完整代码 一、顶点着色器和片段着色器代码分析 1. 着色器1 用到的坐标矩阵, 四个四边形顶点坐标 float vertices_data[36] {// 所…

mybatis之主键返回

1.在mybatis的xml中加入 <insert id"insertUser" keyProperty"id" useGeneratedKeys"true" parameterType"com.UserAndOrder"> insert into Tuser(userName,passWord) values (#{userName},#{passWord} ) </insert&…

多维时序 | MATLAB实现PSO-BiLSTM-Attention粒子群优化双向长短期记忆神经网络融合注意力机制的多变量时间序列预测

多维时序 | MATLAB实现PSO-BiLSTM-Attention粒子群优化双向长短期记忆神经网络融合注意力机制的多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-BiLSTM-Attention粒子群优化双向长短期记忆神经网络融合注意力机制的多变量时间序列预测预测效果基本介绍模型描述程序设计参考…

国产高云FPGA开发软件Gowin的下载、安装、Licence共享,按照我的方案保证立马能用,不能用你铲我耳屎

目录 1、前言2、GOWIN简介3、GOWIN下载4、GOWIN安装5、Licence共享方案&#xff0c;立马就能用6、网盘福利领取 1、前言 “苟利国家生死以&#xff0c;岂因祸福避趋之&#xff01;”大洋彼岸的我优秀地下档员&#xff0c;敏锐地洞察到祖国的短板在于高精尖半导体的制造领域&am…

unity http下载资源

直接下载不显示进度 private void OnDownloadAssets()//下载资源{StartCoroutine(DownloadFormServer_IE(url, savePath));}//其他方法private IEnumerator DownloadFormServer_IE(string url, string path)//从服务器下载资源{Debug.Log("正在下载" url);UnityWebR…

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 解决方案 解决方案 ssh-keygen -f "/home/oyk/.ssh/known_hosts" -R "[192.168.30.125]:6004"再重连就行

使用IDEA 将Eclipse java工程转为maven格式

使用IDEA 将Eclipse java工程转为maven格式 ①使用idea打开项目&#xff0c;在项目根目录下右键选择 Add Framework Support 选择 maven &#xff0c;引入maven ②找到项目中的.classpath文件或者lib目录 根据.classpath文件或者lib目录中列举的jar包名&#xff0c;将其依次手…

JS-Number数字类型详解

一、前言 与其他语言不同&#xff0c;在JS中不区分整数与浮点数&#xff0c;统一为浮点数。所有数字类型统一都是基于 IEEE 754 标准来实现&#xff1b;采用的是“双精度”格式&#xff08;即 64 位二进制&#xff09;。这也意味着在小数计算时&#xff0c;会发生精度误差的情…

Redis 配置文件信息中文翻译版

前言 Redis 配置文件信息中文翻译版&#xff0c;方便大家阅读和理解对应参数信息及配置参数信息 # Redis configuration file example# Note on units: when memory size is needed, it is possible to specify # it in the usual form of 1k 5GB 4M and so forth: # 注意:当…

信息检索与数据挖掘 | 【实验】检索评价指标MAP、MRR、NDCG

文章目录 &#x1f4da;实验内容&#x1f4da;知识梳理&#x1f4da;实验步骤&#x1f407;前情提要&#x1f407;MAP评价指标函数&#x1f407;MRR 评价指标函数&#x1f407;NDCG评价指标函数&#x1f407;调试结果 &#x1f4da;实验内容 实现以下指标评价&#xff0c;并对…

【ICE】webrtc lite 1:cmake构建

p2ptransportchannel 是 ICE 实现基于此实现了DTLTransport而前者是独立的模块。依赖库较少主要是ssl absl OpenSSL Protobuf 可选 absl webrtc 不支持大端 :big endian architectures defined in WebRTC’s arch.h D_WINSOCKAPI_ 用来做啥? 以下编译选项: add_compile_opti…

锐捷EG易网关login.php以及其后台cli.php/branch_passw.php RCE漏洞复现 [附POC]

文章目录 锐捷EG易网关login.php以及其后台cli.php/branch_passw.php远程代码执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 锐捷EG易网关login.php以及其后台cli.php/branch_passw.php远程代码执行漏洞复…

【Java 进阶篇】JQuery 案例:下拉列表选中条目左右移动,打破选择的边界

在前端的舞台上&#xff0c;下拉列表是常见的用户交互元素&#xff0c;但有时候我们想要更多的交互体验。通过巧妙运用 JQuery&#xff0c;我们可以实现下拉列表中选中条目的左右移动功能&#xff0c;为用户提供更加灵活的选择方式。本篇博客将深入研究 JQuery 中实现这一功能的…

分享一套 MT4 crm MT4 MT5 CRM源码、web trade交易系统

一套MT4 MT5 CRM源码&#xff0c;有跟单社区&#xff0c;同时支持MT4进行对接使用&#xff0c;支持代理返佣自由进行设置&#xff0c;可自动实时同步manager后台分组、交易品种和客户所有信息。包括带有内部实时内转功能&#xff0c;支持任何第三方支付、区块链和电子钱包。 整…

操作系统(二 )| 进程控制 进程状态 进程描述 进程控制 进程同步互斥

文章目录 1 进程和程序区别2 进程状态2.1 进程的5种基本状态2.2 进程状态之间转换2.3 七状态模型 3 进程描述3.1 进程控制块 PCB3.2 进程块组织方式 4 进程控制5 进程同步 互斥5.1 区分进程互斥和同步5.2 核心方案5.3 其他方案方案1 设置锁变量方案2 严格轮转法方案3 Peterson解…

vue自定义指令使用

实现 注册一个自定义指令有全局注册与局部注册 全局注册主要是通过Vue.directive方法进行注册 Vue.directive第一个参数是指令的名字&#xff08;不需要写上v-前缀&#xff09;&#xff0c;第二个参数可以是对象数据&#xff0c;也可以是一个指令函数 // 注册一个全局自定义指…

post 和get参数 请求

json参数 post请求格式 RestController public class HelloController { //json参数 post 请求RequestMapping("/jsonParam")public String jsonParam(RequestBody User user){System.out.println(user);return "OK";} } postman 接口测试工具…