Javascript中的宏任务与微任务

事件循环

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。Event Loop 包含两类:一类是基于 Browsing Context,一种是基于 Worker。二者的运行是独立的,也就是说,每一个 JavaScript 运行的"线程环境"都有一个独立的 Event Loop,每一个 Web Worker 也有一个独立的 Event Loop。

本文所涉及到的事件循环是基于 Browsing Context。

任务队列

根据规范,事件循环是通过任务队列的机制来进行协调的。一个 Event Loop 中,可以有一个或者多个任务队列(task queue),一个任务队列便是一系列有序任务(task)的集合;每个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不同源来的则被添加到不同队列。setTimeout/Promise 等API便是任务源,而进入任务队列的是他们指定的具体执行任务。

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

在此次 tick 中选择最先进入队列的任务(oldest task),如果有则执行(一次)
检查是否存在 Microtasks,如果存在则不停地执行,直至清空 Microtasks Queue
更新 render
主线程重复执行上述步骤

在上诉tick的基础上需要了解几点:

JS分为同步任务和异步任务
同步任务都在主线程上执行,形成一个执行栈
主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。
一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

宏任务

(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,流程如下:

(macro)task->渲染->(macro)task->…
宏任务包含:

script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务

microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

微任务包含:

Promise.then
Object.observe
MutationObserver
process.nextTick(Node.js 环境)
运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

执行一个宏任务(栈中没有就从事件队列中获取)
执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

如图:
jstask.png

实例讲解
实例1
setTimeout(function(){console.log('定时器开始啦')});new Promise(function(resolve){console.log('马上执行for循环啦');for(var i = 0; i < 10000; i++){i == 99 && resolve();}}).then(function(){console.log('执行then函数啦')});console.log('代码执行结束');//马上执行for循环啦 //代码执行结束 //执行then函数啦 //定时器开始啦

首先执行script下的宏任务,遇到setTimeout,将其放到宏任务的【队列】里

遇到 new Promise直接执行,打印"马上执行for循环啦"

遇到then方法,是微任务,将其放到微任务的【队列里】

打印 “代码执行结束”

本轮宏任务执行完毕,查看本轮的微任务,发现有一个then方法里的函数, 打印"执行then函数啦"

到此,本轮的event loop 全部完成。

下一轮的循环里,先执行一个宏任务,发现宏任务的【队列】里有一个 setTimeout里的函数,执行打印"定时器开始啦"

实例2
async function async1() {console.log( 'async1 start' )await async2()console.log( 'async1 end' )
}
async function async2() {console.log( 'async2' )
}
async1()
console.log( 'script start' )//async1 start
//async2
//script start
//async1 end

一旦遇到 await 就立刻让出线程,阻塞后面的代码

等候之后,对于 await 来说分两种情况

不是 promise 对象
如果不是 promise,await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完毕后,在回到async内部,把promise的东西,作为await表达式的结果

是promise对象
如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。

实例3
       new Promise( ( resolve, reject ) => {console.log( "promise1" )resolve()} ).then( () => {console.log( 1 )} ).then( () => {console.log( 2 )} ).then( () => {console.log( 3 )} )new Promise( ( resolve, reject ) => {console.log( "promise2" )resolve()} ).then( () => {console.log( 4 )} ).then( () => {console.log( 5 )} ).then( () => {console.log( 6 )} )//1-4-2-5-3-6

先执行同步代码 promise1, promise2,此时微任务有两个任务 log(1)和log(4)

执行完log(1)和log(4)此时任务中有log(2)和log(5)两个微任务

执行log(2)和log(5)此时任务中有log(3)和log(6)两个微任务

连续的几个then()回调,并不是连续的创建了一系列的微任务并推入微任务队列,因为then()的返回值必然是一个Promise,而后续的then()是上一步then()返回的Promise的回调

实例4
setTimeout(() => console.log('setTimeout1'), 0);  //1宏任务
setTimeout(() => {								//2宏任务console.log('setTimeout2');Promise.resolve().then(() => {console.log('promise3');Promise.resolve().then(() => {console.log('promise4');})console.log(5)})setTimeout(() => console.log('setTimeout4'), 0);  //4宏任务
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);  //3宏任务
Promise.resolve().then(() => {//1微任务console.log('promise1');
})//promise1
//setTimeout1
//setTimeout2
//promise3
//5
//promise4
//setTimeout3
//setTimeout4

在这里插入图片描述

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

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

相关文章

购买Zoho CRM系统要花多少钱?

相信对CRM系统有过了解的人都知道&#xff0c;CRM系统的价格取决于功能需求&#xff0c;用户数量&#xff0c;部署方式&#xff0c;定制开发等因素。Zoho CRM是全球领先的云CRM系统&#xff0c;自2005年推出以来&#xff0c;累计服务25万企业&#xff0c;那么Zoho CRM系统的价格…

python批量修改文件夹下的后缀名

python批量修改文件夹下的后缀名 &#xff08;所有的.txt结尾的文件&#xff0c;替换成.py结尾&#xff09; 1、需要将某个文件夹下所有的.txt结尾的文件&#xff0c;替换成.py结尾 2、Python代码&#xff1a; import os# 指定需要更改文件的目录 dir_path D:/study/py/4#…

Vatee万腾数字引领未来:vatee科技力量的独特路径

在当今数字化浪潮的推动下&#xff0c;Vatee万腾以其卓越的科技力量&#xff0c;正引领着未来的数字化时代&#xff0c;描绘着一条独特的发展路径。通过持续创新、前瞻思维和对技术的深度理解&#xff0c;Vatee万腾正在为未来的科技发展创造新的可能性&#xff0c;塑造着数字引…

微信开放平台Android平台应用签名怎么填写

winR 输入cmd 进到本地签名文件的目录下 输入 keytool -list -v -keystore <keystore文件路径> -alias <别名>请将 <keystore文件路径> 替换为您的密钥库文件&#xff08;通常是 .jks 或 .keystore 文件&#xff09;的路径&#xff0c;而 <别名> 则是…

Speaker Verification,声纹验证详解——语音信号处理学习(九)

参考文献&#xff1a; Speaker Verification哔哩哔哩bilibili 2020 年 3月 新番 李宏毅 人类语言处理 独家笔记 声纹识别 - 16 - 知乎 (zhihu.com) (2) Meta Learning – Metric-based (1/3) - YouTube 如何理解等错误率(EER, Equal Error Rate)&#xff1f;请不要只给定义 - 知…

oracle数据库巡检常见脚本-系列二

简介 作为数据库管理员&#xff08;DBA&#xff09;&#xff0c;定期进行数据库的日常巡检是非常重要的。以下是一些原因&#xff1a; 保证系统的稳定性&#xff1a;通过定期巡检&#xff0c;DBA可以发现并及时解决可能导致系统不稳定的问题&#xff0c;如性能瓶颈、资源利用率…

人工智能:让生活更便捷、更智能——探讨人工智能在生活中的作用与挑战

文章目录 前言人工智能的定义与分类人工智能的领域一、智能语音助手改变日常生活二、智能驾驶带来出行革命三、人工智能在医疗健康领域的应用四、教育领域的人工智能创新 人工智能的应用生活方面的影响工作方面的影响 应对AI带来的挑战后记 前言 人工智能相关的领域&#xff0…

Python基于机器学习模型LightGBM进行水电站流量入库预测项目源码+数据集+模型,含项目报告

1.前言 该文档主要是介绍通过机器学习模型LightGBM进行水电站流量入库预测。 对于水电站来说&#xff0c;发电是主要经济效益来源&#xff0c;而水就是生产的原料。对进入水电站水库的入库流量进行精准预测&#xff0c;能够帮助水电站对防洪、发电计划调度工作进行合理安排&…

女娃娃就要打扮,就要时刻保持美丽

超足充绒量&#xff0c;细腻柔软 上身效果很棒保暖性也很强 无论是日常出行还是户外活动 穿这件羽绒服都妥妥的 简约时尚的色彩搭配 使它在寒冷的冬季 既能保暖又能展现个人品味哦&#xff01;

创建vue项目体验

文章目录 使用vue-cli创建vue项目创建出的项目目录结构配置router 运行问题router未找到eslint报错 首页显示单页面内容替换 使用vue-cli创建vue项目 安装vue-cli&#xff0c;创建基本项目 选择步骤 一般创建成功后&#xff0c;提示使用下面的指令运行demo npm run serve创建…

【开源项目】热点监测降级框架Akali源码解读

项目地址 https://gitee.com/dromara/Akali 项目介绍 Akali&#xff08;阿卡丽&#xff09;是一个轻量级本地化热点检测/降级框架&#xff0c;适用于大流量场景&#xff0c;可轻松解决业务中超高流量的并发查询等场景。并且接入和使用极其简单&#xff0c;10秒钟即可接入使用&a…

Visual NLP:图像信息自动提取的未来

本文旨在以简单的方式解释 Visual NLP 的关键概念&#xff0c;让你了解 Visual NLP 的含义、它的用例是什么、如何使用它以及为什么它是构建自动提取管道的未来 。 NSDT在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在…

一站式解决Mac音视频转换需求——Xilisoft Video Converter Ultimate for Mac

在数字化时代&#xff0c;音视频的应用越来越广泛&#xff0c;不同的设备和平台对音视频格式的要求也不尽相同。因此&#xff0c;如何找到一款功能强大、易于操作的音视频转换软件成为了Mac用户的迫切需求。而Xilisoft Video Converter Ultimate for Mac&#xff08;曦力音视频…

4.18每日一题(极坐标累次积分到直角坐标累次积分的转换)

注&#xff1a;rdr化为直角坐标以后r直接消去了&#xff0c;不需要计算

可编程交流回馈式负载箱在电源设备中的应用

可编程交流回馈式负载箱可以用于测试电源设备的输出能力&#xff0c;通过在负载箱中设置不同的负载条件&#xff0c;可以模拟不同的工作负载情况&#xff0c;从而测试电源设备在不同负载下的输出能力和稳定性。这对于电源设备的设计和生产非常重要&#xff0c;可以帮助制造商评…

SELinux refpolicy详解(1)

本文部分内容参考&#xff1a; SELinux - ArchWiki SELinux_百度百科 一、SELinux介绍 1. SELinux简介 SELinux&#xff08;Security-Enhanced Linux&#xff0c;安全增强型Linux&#xff09;是美国国家安全局&#xff08;NSA&#xff09;对于强制访问控制的实现&#xff0…

HarmonyOS ArkTS Video组件的使用(七)

概述 在手机、平板或是智慧屏这些终端设备上&#xff0c;媒体功能可以算作是我们最常用的场景之一。无论是实现音频的播放、录制、采集&#xff0c;还是视频的播放、切换、循环&#xff0c;亦或是相机的预览、拍照等功能&#xff0c;媒体组件都是必不可少的。以视频功能为例&a…

CVE-2022-21661

简介 CVE-2022-21661是一个与WordPress相关的漏洞&#xff0c;涉及到SQL注入问题。该漏洞主要源于WordPress的WQ_Tax_Query类中的clean_query函数&#xff0c;可能允许攻击者通过控制传递给该函数的数据来控制生成的SQL查询&#xff0c;从而执行任意的SQL代码。 当WordPress的…

【ROS 2 进阶-MoveIt!】MoveIt!中的关键节点

所有内容请查看&#xff1a;博客学习目录_Howe_xixi的博客-CSDN博客 原文档链接&#xff1a;Docs

什么是索引下推

索引下推介绍 索引下推&#xff08;INDEX CONDITION PUSHDOWN&#xff0c;简称 ICP&#xff09;是在 MySQL 5.6 针对扫描二级索引的一项优化改进。总的来说是通过把索引过滤条件下推到存储引擎&#xff0c;来减少 MySQL 存储引擎访问基表的次数以及 MySQL 服务层访问存储引擎的…