(转)JS事件循环和宏任务和微任务

news/2024/2/28 2:03:42

一 进程与线程

进程和线程的概念用较为官方的术语描述来说是这样的

 

1.进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
2.线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

用LOL来比喻的话(举例子可能不太贴切,因为本人比较喜欢玩lol 所以用这个举例子让自己来加深印象)

 

一个进程就是一局游戏,每一局游戏都要有野怪小兵这些资源;
每局游戏都相互独立互不干涉;
一个线程就是一个英雄;
一局游戏里有多个英雄(一个进程有多个线程);
英雄之间共享资源

映射关系为

 

一局游戏的野怪和小兵 > 系统分配的内存
每一局游戏相互独立 > 进程之间相互独立
打团战 -> 多个线程在进程中协作完成任务
一局游戏可能一个玩也可能多个人玩>一个进程由一个或多个线程组成
英雄之间共享野怪小兵谁都可以吃 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)

二 浏览器是多进程的

浏览器可以运行是因为系统给分配了资源和内存,浏览器每一个tab页都需要资源和内存,所以每一个tab页面都对应至少一个进程,在这里浏览器应该也有自己的优化机制,有时候打开多个tab页后,可以在Chrome任务管理器中看到,有些进程被合并了 (所以每一个Tab标签对应一个进程并不一定是绝对的)
知道了浏览器是多进程后,再来看看它到底包含哪些进程:(为了简化理解,仅列举主要进程)

1. Browser进程

 

浏览器的主进程(负责协调、主控),只有一个。
负责浏览器界面显示,与用户交互。如前进,后退等
负责各个页面的管理,创建和销毁其他进程
将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
网络资源的管理,下载等

2. 第三方插件进程

 

每种类型的插件对应一个进程,仅当使用该插件时才创建 

3. GPU进程

 

最多一个,用于3D绘制等 

4. 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的)

 

默认每个Tab页面一个进程,互不影响。
主要作用为
页面渲染,脚本执行,事件处理等

三 浏览器渲染进程

作为前端开发工程师我们最主要的关注点还是渲染进程。
可以这样理解,页面的渲染,JS的执行,事件的循环,都在这个进程内进行,渲染进程是多线程的
接下来重点分析这个进程的常驻线程。

1.GUI渲染进程

 

1.负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
2.当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。
3.注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

2.JS引擎线程

 

1.也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
2.JS引擎线程负责解析Javascript脚本,运行代码。
3.JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
4.同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

3.事件处理线程

 

1.归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
2.当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中
3.当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
4.注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

4.定时器线程

 

1.传说中的setInterval与setTimeout所在线程
2.浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
3.因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
4.注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。

5.http异步请求线程

 

1.在XMLHttpRequest在连接后是通过浏览器新开一个线程请求2.将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。

image

四 事件循环

上文说了几个线程

 


js引擎线程
事件触发线程
定时触发器线程

然后再理解一个概念:

 

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

image

 

image

 

主线程运行时会产生执行栈,栈中的代码调用某些api时,它们会在事件队列中添加各种事件(当满足触发条件后,如ajax请求完毕)
而栈中的代码执行完毕,就会读取事件队列中的事件,去执行那些回调
如此循环
注意,总是要等待栈中的代码执行完毕后才会去读取事件队列中的事件

五 宏任务微任务

上文中将JS事件循环机制梳理了一遍,在ES5的情况是够用了,但是在ES6盛行的现在,仍然会遇到一些问题,譬如下面这题:

 

console.log('script start');
setTimeout(function() {console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {console.log('promise1');
}).then(function() {console.log('promise2');
});
console.log('script end');

它的正确执行顺序是这样子的:

 

script start
script end
promise1
promise2
setTimeout

为什么呢?因为Promise里有了一个一个新的概念:microtask。微任务
JS中分为两种任务类型:macrotask和microtask,在ECMAScript中,microtask称为jobs,macrotask可称为task。
它们的定义?区别?简单点可以按如下理解:

 

macrotask(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)
每一个task会从头到尾将这个任务执行完毕,不会执行其它
浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个 task 执行开始前,对页面进行重新渲染

 

microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务
也就是说,在当前task任务后,下一个task之前,在渲染之前
所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染
也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)

分别很么样的场景会形成macrotask和microtask呢?

 

macrotask:主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)
microtask:Promise,process.nextTick等

再根据线程来理解下:

 

macrotask中的事件都是放在一个事件队列中的,而这个队列由事件触发线程维护
microtask中的所有微任务都是添加到微任务队列(Job Queues)中,等待当前macrotask执行完毕后执行,而这个队列由JS引擎线程维护(这点由自己理解+推测得出,因为它是在主线程下无缝执行的)

所以,总结下运行机制:

 

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

image

参考文章
全面梳理JS引擎的运行机制
https://mp.weixin.qq.com/s?__biz=MzUzMjA3MTI2NQ==&mid=2247485214&idx=1&sn=12decb0ba6b6060d6b9f88ee6c227d7e&chksm=fab99110cdce1806c508950bf2cdb1b09c45fb9a48acbce868694ad980c112ddcee671b0a3f6&mpshare=1&scene=24&srcid=&sharer_sharetime=1585841105377&sharer_shareid=762717275fedf766441eee549354e3af&key=25482536a2868f95a747be1bba6a2a0f336defbbf8d45116a1dc006e3119777adad66c433cd6f4b685e308f086f164107dd3aa1c6b2eedb4d6e3007bab957877ea458e842beb61384aec253a8d3113a5&ascene=14&uin=MTc1MjM1NzM4MQ%3D%3D&devicetype=Windows+7&version=62080079&lang=zh_CN&exportkey=AewYYl61ye1z6y1NiRjiJEQ%3D&pass_ticket=C4is0r6nXq%2FvPIwtVRO8UIjTQ7xNdzevdyWz58B0vV70j5JGHCTivvcazNg4WduX](https://mp.weixin.qq.com/s?__biz=MzUzMjA3MTI2NQ==&mid=2247485214&idx=1&sn=12decb0ba6b6060d6b9f88ee6c227d7e&chksm=fab99110cdce1806c508950bf2cdb1b09c45fb9a48acbce868694ad980c112ddcee671b0a3f6&mpshare=1&scene=24&srcid=&sharer_sharetime=1585841105377&sharer_shareid=762717275fedf766441eee549354e3af&key=25482536a2868f95a747be1bba6a2a0f336defbbf8d45116a1dc006e3119777adad66c433cd6f4b685e308f086f164107dd3aa1c6b2eedb4d6e3007bab957877ea458e842beb61384aec253a8d3113a5&ascene=14&uin=MTc1MjM1NzM4MQ%3D%3D&devicetype=Windows+7&version=62080079&lang=zh_CN&exportkey=AewYYl61ye1z6y1NiRjiJEQ%3D&pass_ticket=C4is0r6nXq%2FvPIwtVRO8UIjTQ7xNdzevdyWz58B0vV70j5JGHCTivvcazNg4WduX

最后附上几道题

 

async function async1() {console.log('async1 start');await async2();console.log('async1 end');}async function async2() {console.log('async2');}console.log('script start');setTimeout(function() {console.log('setTimeout');}, 0)async1();new Promise(function(resolve) {console.log('promise1');resolve();}).then(function() {console.log('promise2');})console.log('script end');

 

console.log('1');setTimeout(function() {console.log('2');new Promise(function(resolve) {console.log('3');resolve();}).then(function() {console.log('4');})})new Promise(function(resolve) {console.log('5');resolve();}).then(function() {console.log('6');})setTimeout(function() {console.log('7');})setTimeout(function() {console.log('8');new Promise(function(resolve) {console.log('9');resolve();}).then(function() {console.log('10');})})new Promise(function(resolve) {console.log('11');resolve();}).then(function() {console.log('12');})console.log('13');

 

const promise = new Promise((resolve, reject) => {console.log("1");setTimeout(() => {console.log("2");setTimeout(() => {console.log('4');})resolve('success');}, 1000)})console.log('3');promise.then((res) => {return new Error('error!!!')}).then((res) => {console.log('then:', res)}).catch((err) => {console.log('catch:', err)})promise.then((res) => {console.log(res)}).catch((err) => {console.log('catch:', err);})



链接:https://www.jianshu.com/p/c3756648e921


http://www.ppmy.cn/news/705623.html

相关文章

CTF逆向总结(二)

CTF 逆向总结 目录 CTF 逆向总结 题目类型总结: 汇编操作类总结: ASCII码表类总结: 逆向、脚本类总结: 栈、参数、内存、寄存器类总结: 函数类总结: IDA等软件类总结: 算法类总结&…

帧同步(LockStep)该如何反外挂 及 优化

原标题:帧同步(LockStep)该如何反外挂 及 优化 01. 帧同步(LockStep)该如何反外挂 在中国的游戏环境下,反挂已经成为了游戏开发的重中之重,甚至能决定一款游戏的生死,吃鸡就是一个典…

Java学习笔记:2021年12月31日下午-2022年1月1日上午

Java学习笔记:2021年12月31日下午-2022年1月1日上午 摘要:主要记录了计算机的电气构成,学习Linux系统的原因以及关于Linux以及相关操作的基础知识。 文章目录 Java学习笔记:2021年12月31日下午-2022年1月1日上午计算机的电气构成…

单片机怎么通过按键控制计时器的开始和停止_《搞机作战室》机械师PX780控制中心软件使用教程...

我们收到新机器的时候,想要设置键盘颜色、或者要设置风扇速度不知从何下手,要怎么安装驱动、控制中心功能怎么使用!!! 那么接下来由我华仔为大家讲解机械师PX780游戏本控制中心驱动安装和功能使用。 本篇文章分为两部分…

rog live service是什么_「评测」三模无线,微动随心换,华硕ROG 烈刃2满足所有游戏需求...

随着无线技术的提升,越来越多外设厂商开始发力无线外设市场,而作为老牌外设厂商的华硕自然不会“置之事外”。从之前的斯巴达到今年的魔刃,华硕在用行动告诉大家,我不仅要做无线,更要做高端无线。 而在最近,华硕ROG又上线了一款无线蓝牙三模无线游戏鼠标:ROG烈刃2(以下简…

【VC++游戏开发#十】2D篇 —— 人工智能(一):滚动地图 用鼠标控制人物的走动

本文由BlueCoder编写 转载请说明出处: http://blog.csdn.net/crocodile__/article/details/18039107 我的邮箱:bluecoderyeah.net 欢迎大家和我交流编程心得 我的微博:BlueCoder_黎小华 欢迎光临^_^ 和大家交流一下哈: 我…

Unity Shader-描边效果

简介 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果。最近又跑回去玩了玩《剑灵》,虽然出了三年了,感觉在现在的网游里面画面仍然算很好的了,剑灵里面走近或者选中N…

提升windows使用效率的软件

文件管理类 快速查找文件:Everything 如果你有搜索习惯,而不是手动去翻文件夹,这个软件也许你用的上。 轻量、不占内存。可以让你在几秒钟内搜索出在你硬盘上的文件,无论这个文件藏得有多深。 提升打开文件的效率:L…

不知道ai自动生成绘画网站有哪些就试试这些ai绘画软件

自然语言处理技术和机器学习的不断发展,为艺术创作和设计领域带来了新的可能性。随着人工智能技术的进步,越来越多的网站和平台开始利用ai技术,为大家提供自动生成绘画的功能。这些ai绘画网站通过深度学习和生成对抗网络等先进技术&#xff0…

Java Zip 教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 java.util.zip提供用于读写标准 ZIP 和 GZIP 文件格式的类,还包括使用 DEFLATE 压缩算法(用于 ZIP 和 GZIP 文件格式)对数据进行压缩和解压缩的类。此外,还存在用于计算任意输入流的 CRC-32 和 Adler-32 校验和的实用工…

苹果混合硬盘合并

CommandR重启系统,打开终端,合并磁盘: 进入终端 diskutil list diskutil cs create Macintosh\ HD disk0 disk1 diskutil cs list 找到Logical Volume Group 的标示(数字和英文的组合,如上图:混合硬盘L…

怎样在苹果电脑上用移动硬盘(使用NTFS格式硬盘)?

亲测太好用啦啊啊啊啊啊啊啊啊啊啊啊啊啊 mac系统天生支持NTFS,只不过挂载方式是read-only方式,需要手动把分区改成可写方式。 需要一点点终端操作。。 流程如下: 1、插入硬盘,终端执行 mount | grep ntfs,查看挂载方式&#…

黑苹果入门:名词解释篇

系统篇 1、麦金塔什电脑/Macintosh:麦金塔什是音译,指苹果公司推出的个人电脑系列,取名于一种苹果的品种,和砸到牛顿的苹果、艾兰图灵自杀的苹果没有关系。Macintosh简称Mac;另外你也可能会看到“Hackintosh”这个词&a…

苹果Mac 无法读写NTFS格式的U盘或移动硬盘?一次解决

Mac 默认只能读取NTFS 格式的U盘或移动硬盘,因为写入权限被隐藏封闭了。所以我们只要开启它就可以了。通过下面的办法你就可以轻松的为你的U盘或移动硬盘开启写入权限。(也就是说你可以把文件从你的U盘或移动硬盘里面拖出来,也可以把文件拖进…

苹果电脑的文件怎样拷贝入移动硬盘里

这两天有点烦,新购Mac的喜悦心情全没了,恨不得把它人道毁灭——电脑里的文件竟然不能拷贝到移动硬盘上,这是什么烂系统。 后来用Mac里的磁盘工具把移动硬盘格式化后,Mac上的文件能拷贝到移动硬盘里了。 可是把移动硬盘接回PC上&a…

mac怎么删除硬盘里面的东西?为什么苹果电脑无法删除移动硬盘文件?

mac怎么删除硬盘里面的东西?由于移动硬盘的文件系统是NTFS格式的,而这种格式与Mac电脑是不兼容的,Mac电脑没有权限对移动硬盘上的数据进行操作,Mac上不能把移动硬盘的数据删除了,那么,有没有什么操作方法&a…

苹果电脑MacOS连接使用移动硬盘

前言 苹果电脑不是高配版本的情况下,随着使用越来越久存储会不太够用。这时候使用移动硬盘是一种比较常见的选择。移动硬盘买回来时默认是NTFS格式,也就是windows系统的文件格式,苹果电脑能读取硬盘文件,但不能写入。 解决移动硬盘…

苹果电脑硬盘读写软件有哪些?Tuxera NTFS2023mac读写硬盘软件

格式化是将硬盘重置到初始状态或者是转换硬盘格式所需的一项重要步骤,格式化可以解决大部分用户遇到的硬盘问题,不过在进行格式化之前,大家需要提前了解格式化的具体注意事项,以避免不必要的损失。下面本文就来着重介绍磁盘格式化…

苹果电脑怎么删除移动硬盘里的文件,苹果电脑无法删除移动硬盘文件

苹果电脑怎么删除移动硬盘里的文件?也不能进行复制、编辑、移动等操作,只能够打开文件进行查阅,是因为移动硬盘是NTFS格式的,这种格式在Mac电脑上只允许被查阅。 Mac为何不能正常读写NTFS移动硬盘? Windows电脑支持的…

Mac 如何使用外部存储设备,移动硬盘备份 iPhone 数据

Mac 如何使用外部存储设备,移动硬盘备份 iPhone 数据 一、问题描述 前段时间碰到一个问题,我 iPhone 背板碎了,需要走 AppleCare 交给苹果返厂维修,而我的 iPhone 是 512GB 的,在备份数据时候麻烦了,我笔…
最新文章