一文告诉你 Event Loop 是什么?

 

Event Loop 也叫做“事件循环”,它其实与 JavaScript 的运行机制有关。

JS初始设计

JavaScript 在设计之初便是单线程,程序运行时,只有一个线程存在,在特定的时候只能有特定的代码被执行。这和 JavaScript 的用途有关,它是一门浏览器脚本语言,通常是用来操作 DOM 的,如果是多线程,一个线程进行了删除 DOM 操作,另一个添加 DOM,此时该如何处理?所以 JavaScript 在设计之初便是单线程的。

虽然 HTML5 增加了 Web Work 可用来另开一个线程,但是该线程仍受主线程的控制,所以 JavaScript 的本质依然是单线程

线程和进程

进程和线程是操作系统中的概念,在操作系统中,一个任务就是一个进程,比如你在电脑上打开了一个浏览器来观看视频,便是打开了一个浏览器进程,此时又想记录视频中的重要信息,于是你打开了备忘录,这便是一个备忘录进程,系统会为每个进程分配它所需要的地址空间,数据,代码等系统资源。如果把一个进程看做一个小的车间,车间里有很多工人,有的负责操作机器,有的负责搬运材料,每个工人可以看做一个线程,线程可以共享进程的资源。可以说,线程是进程的最小单位,一个进程可以包含多个线程。

执行栈和任务队列

单线程的 JavaScript 一段一段地执行,前面的执行完了,再执行后面的,试想一个,如果前一个任务需要执行很久,比如接口请求、I/O 操作,此时后面的任务只能干巴巴地等待么?干等不仅浪费了资源,而且页面的交互程度也很差。JavaScript 意识到了这个问题,他们将任务分成了同步任务和异步任务,对于二者有不同的处理。

JavaScript 在运行时会将变量存放在堆(heap)和栈(stack)中,堆中通常存放着一些对象,而变量及对象的指针则存放在栈中。JavaScript 在执行时,同步任务会排好队,在主线程上按照顺序执行,前面的执行完了再执行后面的,排队的地方叫执行栈(execution context stack)。JavaScript 对异步任务不会停下来等待,而是将其挂起,继续执行执行栈中的同步任务,当异步任务有返回结果时,异步任务会加入与执行栈不一样的队列,即任务队列(task queue),所以任务队列中存放的是异步任务执行完成后的结果,通常是回调函数。

当执行栈的同步任务已经执行完成,此时主线程闲下来,它便会去查看任务队列是否有任务,如果有,主线程会将最先进入任务队列的任务加入到执行栈中执行,执行栈中的任务执行完了之后,主线程便又去任务队列中查看是否有任务可执行。主线程去任务队列读取任务到执行栈中去执行,这个过程是循环往复的,这便是 Event Loop,事件循环。

网上有张流传甚广的图对这一过程进行了总结,在图中我们可以看到,JavaScript 在运行时产生了堆和栈,ajax、setTimeout 等异步任务被挂起,异步任务的返回结果加入任务队列,主线程会循环往复地读取任务队列中的任务,加入执行栈中执行。

 

(JavaScript 运行机制,图片来源于网络)

宏任务与微任务

异步任务有更深一层的划分,它们是宏任务(macro task)和微任务(micro task),二者的执行顺序也有差别。在上面我们讲到异步任务的结果会进入任务队列中,对于不同的事件类型,宏任务会加入宏任务队列,微任务会加入微任务队列。在执行栈中的同步任务执行完成后,主线程会先查看任务队列中的微任务,如果有没有,则去宏任务队列中取出最前面的一个事件加入执行栈中执行;如果有,则将所有在微任务队列中的事件依次加入执行栈中执行,直到所有事件执行完成后,再去宏任务中取出最前面的一个事件加入执行栈,如此循环往复。

由此我们可以得出结论,主线程总是会先查看微任务队列,等到微任务队列中的事件都处理完成后,再去宏任务队列中添加一个事件到任务栈中执行。

常见的宏任务有 setTimeout,setInterval;常见的微任务有 new Promise。

代码例子体验

console.log(1)setTimeout(function() {console.log(2)new Promise(function(resolve) {console.log(3)resolve(4)}).then(function(num) {console.log(num)})
}, 300)new Promise(function(resolve) {console.log(5)resolve(6)
}).then(function(num) {console.log(num)
})setTimeout(function() {console.log(7)
}, 400)

我们一步步来分析上面的执行顺序,当程序开始执行时,首先打印出 1,然后遇到了 setTimeout,主程序将它挂起,300 毫秒后它的回调函数进入宏任务队列,我们记做 setTimeout1。随后遇到了 new Promise,resolve 部分是同步执行的,所以会打印出 5,then 中的回调函数进入微任务队列,我们暂时记做 promise1。最后是 setTimeout,同理在 400 毫秒后加入了宏任务队列,我们记做 setTimeout2。

此时任务队列的情况如下:

宏任务

微任务

setTimeout1

promise1

setTimeout2

 

执行栈中的同步任务执行完成后,主线程查看任务队列时发现存在微任务,于是把 promise1 执行了,打印出 6。此时微任务队列已经空了,于是开始查看宏任务队列,将 setTimeout1 的回调函数加入任务栈开始执行,于是首先打印出 2,之后是 3,再将 then 中的回调函数加入微任务队列,我们记做 promise2。

此时任务队列的情况如下:

宏任务

微任务

setTimeout2

promise2

此时执行栈也空了,于是将微任务 promise2 加入执行栈,打印出 4。此时微任务已经执行完,再查看宏任务队列,于是执行 setTimeout2,打印出 7。

所以代码中的输出顺序是 1,5,6,2,3,4,7。

注意,主线程对微任务的读取是逐个读取,直到微任务队列为空,再读取宏队列,对宏任务队列的读取在一个循环中只读取一个。

小结

我们了解了 JavaScript 的运行机制,它是单线程的。JavaScript 中的任务可分为同步任务和异步任务,同步任务总是先进入执行栈中执行,异步任务会被挂起,直到有结果返回时,异步任务会进入任务队列中等待主线程读取执行。当执行栈为空时,主线程便会循环往复地读取任务队列中的事件,进入执行栈执行,这个过程叫 Event Loop。主线程对任务队列的读取也有先后之分,首先会去查找微任务,微任务队列的事件都执行完毕后,再读取最前面的宏任务进行执行,执行完再读取微任务队列,这个过程也是循环往复的。

 

转载于:https://www.cnblogs.com/Joe-and-Joan/p/10687551.html

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

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

相关文章

Spring Boot -Shiro配置多Realm

2019独角兽企业重金招聘Python工程师标准>>> 核心类简介 xxxToken:用户凭证 xxxFilter:生产token,设置登录成功,登录失败处理方法,判断是否登录连接等 xxxRealm:依据配置的支持Token来认证用户信…

idea工具debug断点红色变成灰色

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 没事别瞎点,禁用了断点当然不走了 转自:https://blog.csdn.net/anlve512/article/details/54583469

2020-3-20前端题目

题目一&#xff1a; 判断checked复选框是否有被选中 <!DOCTYPE html> <html> <head> <meta charset" utf-8"> <script> window.onload () > {let odivdocument.getElementById("ant");let ckdocument.getElementById(&…

2020-3-21

题目一&#xff1a; JavaScript 获取月份最后一天日期 月份最后一天日期可能是不同的&#xff0c;比如有的是30、有的是31还有的是28。 <!DOCTYPE html><html> <head> <meta charset" utf-8"> <script type"text/javascript"&…

解决: Unable to connect to zookeeper server within timeout: 5000

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 一个项目启动不起来了&#xff0c;报错如题&#xff1a; Caused by: org.I0Itec.zkclient.exception.ZkTimeoutException: Unable to c…

TeamViewer13 -- 安装、使用说明

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Teamviewer13是一款强大的远程桌面控制工具&#xff0c;同时也是一款非常实用的共享文件传输工具&#xff0c;它拥有简洁的界面以及方便快…

论程序员的自我修炼

摘要&#xff1a;软件开发是个挑战&#xff0c;尤其是对于那些完美主义的程序员。为了想要成为更好的程序员&#xff0c;总会开发出一些特别的功能&#xff0c;在软件设计上想要做到零瑕疵&#xff0c;但事实上&#xff0c;完美的软件设计是根本不存在的&#xff0c;试着让你的…

利用 Charles Proxy 下载旧版本 iOS App

一、软件准备 1、旧版本 iTunes1.IPSW Downloads&#xff1a;https://ipsw.me/2.百度网盘链接&#xff1a;https://pan.baidu.com/s/1PO9Z12o-rqZ_JG68zRqEnA 提取码&#xff1a;fe1v 2、抓包工具 Charles Proxy1.Charles官网链接&#xff1a;https://www.charlesproxy.com/2.百…

禅道8.2-9.2.1注入GetShell

漏洞分析附上某老哥的漏洞分析&#xff0c;来了解下原理。 漏洞利用查看版本&#xff1a;访问Url&#xff1a;http://127.0.0.1/zentao/index.php?modegetconfig即可获取禅道的版本号以及一些其他的信息&#xff0c;目前漏洞存在于v8.2~v9.2确定版本号之后&#xff0c;我们就…

Maven 依赖-镜像仓库替换为 -- 阿里云镜像仓库(飞快实现 pom 引入)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 在本地 maven 的 setting 配置文件中加上阿里云镜像地址就行了&#xff1a; 新增配置内容&#xff1a; <!-- 阿里镜像仓库 --><…

清洗肾脏的绝好秘方(图)

清洗肾脏的绝好秘方&#xff1a;只用香菜&#xff0c;可以在家里尝试。不用花多少钱就可清洗你的肾脏。经过多年来&#xff0c;我们的肾脏过滤血液&#xff0c;排除盐&#xff0c;毒素及所有不需要的物质进入我们的身体。随着时日&#xff0c;盐毒积累&#xff0c;这需要进行清…

【案例】数据量猛增,BI分析效率太低怎么破?

2019独角兽企业重金招聘Python工程师标准>>> 近日&#xff0c;Apache Kylin Innovation Meetup 在上海成功举办&#xff0c;有近200位小伙伴来到了现场。此次会议特别邀请到了金融、互联网等行业的技术伙伴分享了 Kylin 在行业中的实操应用 。今天将首先与大家分享演…

您收到一封 2019 阿里云峰会 (北京) 邀请函

为什么80%的码农都做不了架构师&#xff1f;>>> 摘要&#xff1a; 阿里云峰会&#xff08;北京&#xff09;开发者专场以“云原生和可见的云未来”为主题&#xff0c;不仅涵盖 2 场重大发布&#xff0c;更设置人工智能、机器学习、实时计算、云原生实践等国内外最热…

解决Based on configured schedule, the given trigger ‘triggerGroupName_FREEZE_JOB.triggerName_FREEZE...

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 报错如题、如下&#xff1a; Caused by: org.quartz.SchedulerException: Based on configured schedule, the given trigger triggerG…

2020-3-26

题目一&#xff1a; JavaScript 获取第n个li元素 下面有两种方法 <!DOCTYPE html> <html> <head> <meta charset" utf-8"> <style type"text/css"> ul{list-style:none} </style> <script> window.onloadfunct…

高性能、高可靠分布式文件系统 go-fastdfs v1.2.0 发布

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; go-fastdfs是一个基于http协议的分布式文件系统&#xff0c;它基于大道至简的设计理念&#xff0c;一切从简设计&#xff0c;使得它的运维及扩展变得更加简单&#xff0c;它具有高性能、高可靠、…

zookeeper安装教程

1 安装环境 centos 7.4 jdk 1.8 zookeeper是java开发的&#xff0c;可以运行再windows,linux环境。 安装之前需要先安装号jdk. jdk的安装可以参见博文&#xff1a;http://www.cnblogs.com/jepson6669/p/8374699.html 2 安装过程 1 上传文件到Linux上 2 安装 1 解压到/usr/local…

需求规格说明书1.0

1.引言 1.1目的 该文档是关于我们组的记事本安卓APP和网页版本的功能和性能的描述&#xff0c;重点描述了系统的功能需求&#xff0c;并作为系统设计的主要输入。 本文档的预期读者包括&#xff1a;需求分析人员&#xff0c;设计人员&#xff0c;开发人员&#xff0c;项目管理人…

2020-3-30

题目一&#xff1a; JavaScript 将数组原有的顺序打乱 function le(){ //创建一个函数作为sort()函数的参数。return 0.5-Math.random(); //返回一个数字可能大于零也可能小于零&#xff0c;这样就可以实现随机排序功能&#xff0c; } var arr[]; //声明一个空数组。for(var i…

CC-BY-NC-SA (创作共用许可协议)

创作共用许可协议 &#xff08;英语&#xff1a;Creative Commons license&#xff0c;简称CC许可&#xff09; 是一种公共版权许可协议&#xff0c;其允许分发受版权保护的作品。一个创作共用许可&#xff0c;用于一个作者想给他人分享、使用、甚至创作派生作品的权利。创作共…