当前位置: 首页 > 编程日记 > 正文

JS 总结之事件循环

js

众所周知,JavaScript 为了避免复杂,被设计成了单线程。

⛅️ 任务

单线程意味着所有任务都需要按顺序执行,如果某个任务执行非常耗时,线程就会被阻断,后面的任务需要等上一个任务执行完毕才会进行。而大多数非常耗时的任务是网络请求,CPU 是闲着的,所以为了资源的充分运用,便有了异步的概念。

异步便是把这些非常耗时的任务放到一边,其他任务先进行,等处理完其它不需要等待的任务再回头来计算刚刚被放一边的任务。这样就不会阻断线程啦。

就像上面讲述的,后面的任务需要等上一个任务执行完毕才会进行,叫同步任务;把这些非常耗时的任务放到一边,其他任务先进行,叫异步任务

那么问题来了,执行异步任务后会发生什么

? 任务队列

在 stack 之外存在一个任务队列

当异步任务执行完成后,会将一个回调函数(回调函数是在编写异步任务时指定的,用来处理异步的结果)推入任务队列,这些回调函数根据类放入到 tasksmicrotasks 中,最先被推入的函数先被推入 stack 执行,是先进先出的数据结构。由于有定时器这类功能, stack 一般要检查时间后,某些任务才会被执行。

? 事件循环

一旦 stack 没任务了,JavaScript 引擎就会去读取任务队列,这个过程会循环不断,被叫做事件循环。

? setTimeout、setInterval

上文讲的定时功能,依靠 setTimeout、setInterval 提供的定时功能,区别在于 setTimeout 在指定时间后执行一次,而 setInterval 则重复执行。

setTimeout 在任务队列尾部添加了一个事件,在设定的时间后执行。但实际没有这么理想,当任务队列前面的任务非常耗时,回调函数不一定在设置的时间运行。

所以常见的写法 setTimeout(fn, 0),是指定某个任务在 stack 最早可得的空闲时间执行,也就是说,尽可能早得执行。

(注意:HTML5 标准规定了 setTimeout 的第二个参数的最小值(最短间隔),不得低于 4 毫秒,如果低于这个值,就会自动增加。)

⛈ task 与 microtask

先看一个例子:

console.log(1)setTimeout(() => {console.log(2)
}, 0)Promise.resolve().then(() => {console.log(3)}).then(() => {console.log(4)})console.log(5)

打印出来为:1,5,3,4,2。why? ☃️

? 初探

从上文知道,每个线程都有自己的事件循环,都是独立运行的。事件循环里面有 task 队列 和 mircotask 队列,队列里面都按顺序存放着不同的待执行任务,这些任务从不同源划分的。

tasks 包含生成 dom 对象、解析 HTML、执行主线程 js 代码、更改当前 URL 还有其他的一些事件如页面加载、输入、网络事件和定时器事件。从浏览器的角度来看,tasks 代表一些离散的独立的工作。当执行完一个 task 后,浏览器可以继续其他的工作如页面重渲染和垃圾回收。

microtasks 则是完成一些更新应用程序状态的较小任务,如处理 promise 的回调和 DOM 的修改,这些任务在浏览器重渲染前执行。Microtask 应该以异步的方式尽快执行,其开销比执行一个新的 macrotask 要小。Microtasks 使得我们可以在 UI 重渲染之前执行某些任务,从而避免了不必要的 UI 渲染,这些渲染可能导致显示的应用程序状态不一致。

事件循环持续不断运行,按顺序执行 task 队列,如例子中的 setTimeout, 在 tasks 之间,浏览器可以更新渲染。只要 stack 为空,mircotask 队列就会处理,或者在每个 task 的末尾处理。在处理 mircotask 队列期间,新添加的 microtask 添加到队列的末尾并且也会被执行,如上文的 Promise then callback。

大概顺序就是:

第一轮:检查 task 队列 -> 检查 microtask 队列 -> 检查是否需要渲染更新
下 1 至 n 轮:...

☘ 源

一般来说,task 和 microtask 都有哪些:

task:

  • DOM 操作任务:以非阻塞方式插入文档
  • 用户交互任务:鼠标键盘事件、用户输入事件
  • 网络任务
  • IndexDB 数据库操作等 I/O
  • setTimeout / setInterval
  • history.back
  • setImmediate(涉及 node,不在这里讨论,但归纳在这)

microtask:

  • Promise.then
  • MutationObserver
  • Object.observe
  • process.nextTick(涉及 node,不在这里讨论,但归纳在这)
Jake Archibald 大大 说:setImmediate is task-queuing, whereas nextTick is before other pending work such as I/O, so it's closer to microtasks.

? 小试牛刀

尝试分析一下上面的例子:

  • Promise then 的回调被分到了 microtask 队列中
  • 当打印完 5 后,当前 script 已经执行完毕,开始按顺序执行 microtask 队列中的回调,打印了 3
  • 接着遇到了下一个 Promise then 的回调,也会被执行,打印 4,至此,microtask 队列已空,开始下一轮 task
  • 执行下一个 task,打印 2

所以打印了 1,5,3,4,2

? 运行时机

Tasks 按照顺序执行,浏览器可能在它们的间隔渲染视图。

Microtasks 也是按顺序执行的,执行的顺序,在下面两种情况下执行:

1. 在 task 执行完之后执行。

来看一个例子:

var outer = document.querySelector('.outer')
var inner = document.querySelector('.inner')function onClick() {console.log('click')setTimeout(function() {console.log('timeout')}, 0)Promise.resolve().then(function() {console.log('promise')})
}inner.addEventListener('click', onClick)
outer.addEventListener('click', onClick)

在线查看:Edit on CodeSandBox

截图

microtasks

当点击 inner 后,console 打印:click,promise,click,promise,timeout,timeout。

执行过程:(用文字描述看不清楚,画了个图来一步一步根据)

触发 inner 点击之后:

loop1

触发 outer 点击之后:

loop2

2. 当 stack 为空的时候,便执行完 microtask 队列里面的任务。

可以在规范 html 规范: Cleaning up after a callback step 中找到:

If the JavaScript execution context stack is now empty, perform a microtask checkpoint.

我们把上面的例子改一下:

var outer = document.querySelector('.outer')
var inner = document.querySelector('.inner')function onClick() {console.log('click')setTimeout(function() {console.log('timeout')}, 0)Promise.resolve().then(function() {console.log('promise')})
}inner.addEventListener('click', onClick)
outer.addEventListener('click', onClick)inner.click()

加上 inner.click() 这句,情况变得不一样,在线查看:Edit on CodeSandBox

截图

microtasks2

当点击 inner 后,console 打印:click,click,promise,promise,timeout,timeout。

执行过程:(还是画图)

触发 inner 点击之后:

loop3

触发 outer 点击之后:

loop4

这个例子与上一个不同,当执行完第 6 步,并没有检查 microtask 队列,因为 stack 并没为空,script 还在 stack 中。这也说明,上面的规则确保了 microtasks 不打断当前代码执行。

联系Tasks, microtasks, queues and schedules 文中的解释:

... The above rule ensures microtasks don't interrupt JavaScript that's mid-execution. This means we don't process the microtask queue between listener callbacks, they're processed after both listeners.

⛅️ 总结

  1. 事件循环持续不断运行;
  2. 事件循环包含 task 队列和 microtask 队列;
  3. task 队列和 microtask 队列都是按照队列内顺讯执行的,即先进先出;
  4. tasks 之间(执行完 microtasks 之后),浏览器可以更新渲染;
  5. microtasks 不会打断当前代码执行;
  6. 在 task 执行完之后执行,或者当 stack 为空时,检查 microtask 队列并执行其中的任务;
  7. 新添加的 microtask 添加到队列的末尾并且也会被执行;
  8. 事件循环同一时间内只执行一个任务;
  9. 任务一直执行到完成,不能被其他任务抢断。

? 参考

  • HTML Living Standard: event-loops by WHATWG
  • Tasks, microtasks, queues and schedules by Jake Archibald
  • 深入探究 eventloop 与浏览器渲染的时序问题 by An Yan
  • JavaScript 运行机制详解:再谈 Event Loop by 阮一峰
  • 这一次,彻底弄懂 JavaScript 执行机制 by ssssyoki
  • 关于 task 和 microtask 的问答 by 顾轶灵
  • HTML 系列:macrotask 和 microtask by 杨健

相关文章:

设计模式之工厂方法模式(Factory Method)摘录

23种GOF设计模式一般分为三大类:创建型模式、结构型模式、行为模式。 创建型模式包括:1、FactoryMethod(工厂方法模式);2、Abstract Factory(抽象工厂模式);3、Singleton(单例模式);4、Builder(建造者模式)&#xff1b…

SpanBERT:提出基于分词的预训练模型,多项任务性能超越现有模型!

作者 | Mandar Joshi, Danqi Chen, Yinhan Liu, Daniel S. Weld, Luke Zettlemoyer, Omer Levy译者 | Rachel责编 | Jane出品 | AI科技大本营(ID: rgznai100)【导读】本文提出了一个新的模型预训练方法 SpanBERT ,该方法能够更好地表示和预测…

XP与Windows 7(Win7)等操作系统Ghost备份

XP与Windows 7(Win7)等操作系统Ghost备份 2013年5月5日 前提:备份还原win7的话,此种Ghost备份方法只针对没有100MB保留分区的win7安装方式。去掉100MB的方法可以参考《Windows7(win7)系统重装与破解》&…

SSE4.1和SSE4.2 Intrinsics各函数介绍

SIMD相关头文件包括&#xff1a; //#include <ivec.h>//MMX //#include <fvec.h>//SSE(also include ivec.h) //#include <dvec.h>//SSE2(also include fvec.h)#include <mmintrin.h> //MMX #include <xmmintrin.h> //SSE(include mmintrin.h) #…

Nacos v0.7.0:对接CMDB,实现基于标签的服务发现能力

Nacos近期发布了0.7.0版本&#xff0c;该版本支持对接第三方CMDB获取CMDB数据、使用Selector机制来配置服务的路由类型、支持单机模式使用MySQL数据库、上线Node.js客户端&#xff0c;并修复了一些bug。对接CMDB实现就近访问在服务进行多机房或者多地域部署时&#xff0c;跨地域…

数十篇推荐系统论文被批无法复现:源码、数据集均缺失,性能难达预期

作者 | Maurizio Ferrari Dacrema译者 | 凯隐责编 | Jane出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;【导读】来自意大利米兰理工大学的 Maurizio 团队近日发表了一篇极具批判性的文章&#xff0c;剑指推荐系统领域的其他数十篇论文&#xff0c;指出这些论文中基…

crontab 总结

2019独角兽企业重金招聘Python工程师标准>>> 1.写法 每三天执行一次&#xff1a;0 0 */3 * * root command&#xff0c;注意&#xff1a;* * */3 * * root command 这样写是不对的。其它每N小时执行一次也类似 &#xff08;后续补充&#xff09; 转载于:https://…

ubuntu安装thrift

ubuntu环境下安装thrift-0.10.0 1.解压 2.编译安装 ./configure -with-cpp -with-boost -without-python -without-csharp -with-java -without-erlang -without-perl -with-php -without-php_extension -without-ruby -without-haskell -without-go make sudo make install3.是…

AES(Advanced Encryption Standard) Intrinsics各函数介绍

AES为高级加密标准&#xff0c;是较流行的一种密码算法。 SIMD相关头文件包括&#xff1a; //#include <ivec.h>//MMX //#include <fvec.h>//SSE(also include ivec.h) //#include <dvec.h>//SSE2(also include fvec.h)#include <mmintrin.h> //MMX #…

轻松应对Java试题,这是一份大数据分析工程师面试指南

作者 | HappyMint转载自大数据与人工智能&#xff08;ai-big-data&#xff09;导语&#xff1a;经过这一段时间与读者的互动与沟通&#xff0c;本文作者发现很多小伙伴会咨询面试相关的问题&#xff0c;特别是即将毕业的小伙伴&#xff0c;所以决定输出一系列面试相关的文章。本…

【Elasticsearch 5.6.12 源码】——【3】启动过程分析(下)...

版权声明&#xff1a;本文为博主原创&#xff0c;转载请注明出处&#xff01;简介 本文主要解决以下问题&#xff1a; 1、ES启动过程中的Node对象都初始化了那些服务&#xff1f;构造流程 Step 1、创建一个List暂存初始化失败时需要释放的资源&#xff0c;并使用临时的Logger对…

C++中的封装、继承、多态

封装(encapsulation)&#xff1a;就是将抽象得到的数据和行为(或功能)相结合&#xff0c;形成一个有机的整体&#xff0c;也就是将数据与操作数据的源代码进行有机的结合&#xff0c;形成”类”&#xff0c;其中数据和函数都是类的成员。封装的目的是增强安全性和简化编程&…

比尔盖茨护犊子 称iPad让大批用户沮丧

为什么80%的码农都做不了架构师&#xff1f;>>> 在5月6日接受美国CNBC电视台访问时&#xff0c;微软前任掌门人比尔盖茨维护了自家反响不那么好的Surface系列平板电脑&#xff0c;同时他还不忘吐槽了一把iPad。 当 谈到日渐颓败的PC市场时&#xff0c;盖茨称平板电…

小心陷阱:二维动态内存的不连续性

void new_test() {int** pp;pp new int*[10];for(int i0; i<10; i){pp[i] new int[10];}//pp[0], pp[1], ... , pp[9]在内存中连续;//a1 pp[0][0], pp[0][1], ... , pp[0][9]在内存中也是连续的;//a2 pp[1][0], pp[1][1], ... , pp[1][9]在内存中也是连续的;//...//a9 …

超酷炫!Facebook用深度学习和弱监督学习绘制全球精准道路图

作者 | Saikat Basu等译者 | 陆离责编 | 夕颜出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;导读&#xff1a;现如今&#xff0c;即使可以借助卫星图像和绘制软件&#xff0c;创建精确的道路图也依然是一个费时费力的人力加工过程。许多地区&#xff0c;特别是在发…

npm包发布记录

下雪了&#xff0c;在家闲着&#xff0c;不如写一个npm 包发布。简单的 npm 包的发布网上有很多教程&#xff0c;我就不记录了。这里记录下&#xff0c;一个复杂的 npm 包发布&#xff0c;复杂指的构建环境复杂。 整个工程使用 rollup 来构建&#xff0c;其中会引进 babel 来转…

设计模式之单例模式(Singleton)摘录

23种GOF设计模式一般分为三大类&#xff1a;创建型模式、结构型模式、行为模式。 创建型模式包括&#xff1a;1、FactoryMethod(工厂方法模式)&#xff1b;2、Abstract Factory(抽象工厂模式)&#xff1b;3、Singleton(单例模式)&#xff1b;4、Builder(建造者模式)&#xff1…

关于知识蒸馏,这三篇论文详解不可错过

作者 | 孟让转载自知乎导语&#xff1a;继《从Hinton开山之作开始&#xff0c;谈知识蒸馏的最新进展》之后&#xff0c;作者对知识蒸馏相关重要进行了更加全面的总结。在上一篇文章中主要介绍了attention transfer&#xff0c;FSP matrix和DarkRank&#xff0c;关注点在于寻找不…

设计模式之建造者模式(生成器模式、Builder)摘录

23种GOF设计模式一般分为三大类&#xff1a;创建型模式、结构型模式、行为模式。 创建型模式包括&#xff1a;1、FactoryMethod(工厂方法模式)&#xff1b;2、Abstract Factory(抽象工厂模式)&#xff1b;3、Singleton(单例模式)&#xff1b;4、Builder(建造者模式、生成器模式…

[置顶] webservice系列2---javabeanhandler

摘要&#xff1a;本节主要介绍以下两点&#xff0c;1.带javabean的webservice的开发和调用 2.handler的简单介绍及使用1.引言在之前的一篇博客webservice系列1---基于web工程上写一个基本数据类型的webservice中介绍了如何采用axis1.4来完成一个简单的webservice的开发流程(入参…

AI教育公司物灵科技完成战略融资,商汤科技投资

1月2日消息&#xff0c;从相关媒体报道&#xff0c;AI教育公司物灵科技近日完成了商汤的战略融资&#xff0c;本轮融资将用于产品迭代和扩大市场。 此前投资界曾报道&#xff0c;物灵科技已经获得1.5亿元Pre-A轮融资&#xff0c;当时具体资方未透露。 公开资料显示&#xff0…

Python之父发文,将重构现有核心解析器

原题 | PEG Parsers作者 | Guido van Rossum译者 | 豌豆花下猫转载自 Python猫&#xff08;ID: python_cat&#xff09; 导语&#xff1a;Guido van Rossum 是 Python 的创造者&#xff0c;虽然他现在放弃了“终身仁慈独裁者”的职位&#xff0c;但却成为了指导委员会的五位成员…

全面支持三大主流环境 |百度PaddlePaddle新增Windows环境支持

2019独角兽企业重金招聘Python工程师标准>>> PaddlePaddle作为国内首个深度学习框架&#xff0c;最近发布了更加强大的Fluid1.2版本, 增加了对windows环境的支持&#xff0c;全面支持了Linux、Mac、 windows三大环境。 PaddlePaddle在功能完备的基础上&#xff0c;也…

设计模式之原型模式(Prototype)摘录

23种GOF设计模式一般分为三大类&#xff1a;创建型模式、结构型模式、行为模式。 创建型模式包括&#xff1a;1、FactoryMethod(工厂方法模式)&#xff1b;2、Abstract Factory(抽象工厂模式)&#xff1b;3、Singleton(单例模式)&#xff1b;4、Builder(建造者模式、生成器模式…

NFS共享服务挂载时出现“access denied by server while mounting”的解决方法

笔者用的Linuxf发行版本为Centos6.4&#xff0c;以下方法理论上讲对于Fedora, Red Hat均有效&#xff1a; 搭建好NFS服务后&#xff0c;如果用以下的命令进行挂载&#xff1a; # mount -t nfs 172.16.12.140:/home/liangwode/test /mnt 出现如下错误提示&#xff1a; mount.nf…

设计模式之桥接模式(Bridge)摘录

23种GOF设计模式一般分为三大类&#xff1a;创建型模式、结构型模式、行为模式。 创建型模式包括&#xff1a;1、FactoryMethod(工厂方法模式)&#xff1b;2、Abstract Factory(抽象工厂模式)&#xff1b;3、Singleton(单例模式)&#xff1b;4、Builder(建造者模式、生成器模式…

原360首席科学家颜水成正式加入依图科技,任首席技术官

7 月 29 日&#xff0c;依图科技宣布原 360 首席科学家颜水成正式加入&#xff0c;担任依图科技首席技术官&#xff08;CTO&#xff09;一职。依图方面称&#xff0c;颜水成加入后将带领团队进一步夯实依图在人工智能基础理论和原创算法方面的技术优势&#xff0c;为依图在商业…

分布式存储fastdfs安装使用

1.下载地址https://github.com/happyfish100/fastdfshttps://github.com/happyfish100/fastdfs/wiki安装辅助说明文档2.安装编译环境yum install git gcc gcc-c make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim -y三台主机&#xff1a…

Hibernate学习(九)———— 二级缓存和事务级别详讲

序言 这算是hibernate的最后一篇文章了&#xff0c;下一系列会讲解Struts2的东西&#xff0c;然后说完Struts2&#xff0c;在到Spring&#xff0c;然后在写一个SSH如何整合的案例。之后就会在去讲SSM&#xff0c;在之后我自己的个人博客应该也差不多可以做出来了。基本上先这样…

超详细中文预训练模型ERNIE使用指南

作者 | 高开远&#xff0c;上海交通大学&#xff0c;自然语言处理研究方向最近在工作上处理的都是中文语料&#xff0c;也尝试了一些最近放出来的预训练模型&#xff08;ERNIE&#xff0c;BERT-CHINESE&#xff0c;WWM-BERT-CHINESE&#xff09;&#xff0c;比对之后还是觉得百…