事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑。

众所周知,JS是单线程的,即同一时间只能运行一个任务。一般情况下这不会引发问题,但是如果我们有一个耗时较多的任务,我们必须等该任务执行完毕才能进入下一个任务,然而等待的这段时间常常让我们无法忍受,因为我们这段时间什么都不能做,包括页面也是锁死状态。

好在,时代在进步,浏览器向我们提供了JS引擎不具备的特性:Web API。Web API包括DOM API、定时器、HTTP请求等特性,可以帮助我们实现异步、非阻塞的行为。我们可以通过异步执行任务的方法来解决单线程的弊端,事件循环为此而生。

提问QAQ:为什么JavaScript是单线程的?

多个线程表示您可以同时独立执行程序的多个部分。确定一种语言是单线程还是多线程的最简单方法是看它拥有有多少个调用堆栈。JS 只有一个,所以它是单线程语言。

将JS设计为单线程是由其用途运行环境等因素决定的,作为浏览器脚本语言,JS的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。同时,单线程执行效率高。

1. Event Loop旧印象

大家熟悉的关于事件循环的机制说法大概是:主进程执行完了之后,每次从任务队列里取一个任务执行。如图所示,所有的任务分为同步任务和异步任务,同步任务直接进入任务队列-->主程序执行;异步任务则会挂起,等待其有返回值时进入任务队列从而被主程序执行。异步任务会通过任务队列的机制(先进先出的机制)来进行协调。具体如图所示:

同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入任务队列。主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们所熟悉的Event Loop (事件循环)。但是promise出现之后,这个说法就不太准确了。

2. Event Loop 后印象

2.1 理论

这里首先用一张图展示JavaScript的事件循环:

直接看这张图,可能黑人问号已经出现在同学的脑海。。。

这里将task分为两大类,分别是macroTask(宏任务)和microTask(微任务).一次事件循环:先运行macroTask队列中的一个,然后运行microTask队列中的所有任务。接着开始下一次循环(只是针对macroTask和microTask,一次完整的事件循环会比这个复杂的多)。

那什么是macroTask?什么是microTask呢?

JavaScript引擎把我们的所有任务分门别类,一部分归为macroTask,另外一部分归为microTack,下面是类别划分:

macroTask:

setTimeout

setInterval

setImmediate

requestAnimationFrame

I/O

UI rendering

microTask:

process.nextTick

Promise

Object.observe

MutationObserver

我们所熟悉的定时器就属于macroTask,仅仅了解macroTask的机制还是不够的。为直观感受两种队列的区别,下面上代码进行实践感知。

2.2 实践

以setTimeout、process.nextTick、promise为例直观感受下两种任务队列的运行方式。

console.log('main1');

process.nextTick(function() {

console.log('process.nextTick1');

});

setTimeout(function() {

console.log('setTimeout');

process.nextTick(function() {

console.log('process.nextTick2');

});

}, 0);

new Promise(function(resolve, reject) {

console.log('promise');

resolve();

}).then(function() {

console.log('promise then');

});

console.log('main2');

别着急看答案,先以上面的理论自己想想,运行结果会是啥?

最终结果是这样的:

main1

promise

main2

process.nextTick1

promise then

// 第二次事件循环

setTimeout

process.nextTick2

process.nextTick 和 promise then在 setTimeout 前面输出,已经证明了macroTask和microTask的执行顺序。但是有一点必须要指出的是。上面的图容易给人一个错觉,就是主进程的代码执行之后,会先调用macroTask,再调用microTask,这样在第一个循环里一定是macroTask在前,microTask在后。

但是最终的实践证明:在第一个循环里,process.nextTick1和promise then这两个microTask是在setTimeout这个macroTask里之前输出的,这是因为Promises/A+规范规定主进程的代码也属于macroTask。

主进程这个macroTask(也就是main1、promise和main2)执行完了,自然会去执行process.nextTick1和promise then这两个microTask。这是第一个循环。之后的setTimeout和process.nextTick2属于第二个循环

别看上面那段代码好像特别绕,把原理弄清楚了,都一样 ~

requestAnimationFrame、Object.observe(已废弃) 和 MutationObserver这三个任务的运行机制大家可以从上面看到,不同的只是具体用法不同。重点说下UI rendering。在HTML规范:event-loop-processing-model里叙述了一次事件循环的处理过程,在处理了macroTask和microTask之后,会进行一次Update the rendering,其中细节比较多,总的来说会进行一次UI的重新渲染。

3. 小结

总而言之,记住一次事件循环:先运行macroTask队列中的一个,然后运行microTask队列中的所有任务。接着开始下一次循环。

参考文献:

JavaScript Event Loop相关原理解析

深入理解事件循环机制

JavaScript运行机制

以上就是深入分析JavaScript 事件循环(Event Loop)的详细内容,更多关于JavaScript 事件循环(Event Loop)的资料请关注聚米学院其它相关文章!

JAVA script 循环 图片_深入分析JavaScript 事件循环(Event Loop)相关推荐

  1. JavaScript事件循环机制

    众所周知JS是一门单线程执行环境的语言,对于同步任务而言,同一时刻只能执行一个任务,后续的任务都要在当前执行的任务后面排队.这种模式在遇到一些执行时间较长的任务的时候就会出问题,会导致页面失去响应.所 ...

  2. onpaste事件不生效_从实际开发中来看JavaScript事件循环的使用场景

    前言: 本文是介绍结合DOM事件流和JavaScript事件循环解决一个工作中的实际问题的过程,很多东西不只是面试的时候才会用得到 文中涉及到的代码demo地址:drag-and-eventloop ...

  3. 我理解的javascript事件循环(一)

    javascript事件循环分为2种:一种是浏览器端事件循环,一种是node端事件循环. 此文只是捋一捋我对浏览器端事件循环的理解. 前言 我们都知道 JavaScript 是一门单线程语言,这意味着 ...

  4. dom更新到底在javascript事件循环的哪个阶段?「前端每日一题v22.11.17」

    dom更新到底在javascript事件循环的哪个阶段?「前端每日一题v22.11.17」 昨天写了一篇文章,是javascript的事件循环机制,然后在某乎上也发了,在发的时候看到了一个问题,dom ...

  5. 第七期:详解JavaScript运行机制(Event Loop)

    在浏览器中,每个渲染进程都有一个主线程,主线程非常繁忙,既要处理DOM,又要计算样式,还要处理布局,同时还需要处理JavaScript任务以及各种输入事件.此时我们就需要一个系统来统筹调度这么多不同类 ...

  6. C# Task 循环任务_聊聊 JavaScript 的并发、异步和事件循环

    本文作者:Cody Chan,题图来自 Jake Archibald JavaScript 作为天生的单线程语言,社区经常聊 JavaScript 就聊异步.聊 Event Loop,看起来它们好像难 ...

  7. javascript事件循环Event Loop,宏任务与微任务

    1.javascript的运行机制介绍 javascript是单线程的语言,默认情况下一个时间点只能做一件事情,因此引入异步模型javascript是一门解释性脚本语言,即(边解释边运行) 2.阻塞式 ...

  8. [译] 深入理解 JavaScript 事件循环(二)— task and microtask

    引言 microtask 这一名词是 JS 中比较新的概念,几乎所有人都是在学习 ES6 的 Promise 时才接触这一新概念,我也不例外.当我刚开始学习 Promise 的时候,对其中回调函数的执 ...

  9. JavaScript事件循环

    大厂面试题分享 面试题库 后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 一.异步执行原理 1. 单线程的JavaScript 我们知道,JavaScript是一种单线程语言,它主要 ...

最新文章

  1. linux路由信息自动丢失,浅谈用expect实现路由器自动备份数据
  2. 《一个程序员的奋斗史》正式上架~
  3. root用户登录mysql后新建用户提示1045错误
  4. law是什么的缩写_Lawyer和Attorney 有什么不同?
  5. 怎么将ip地址改成域名访问_什么是域名解析?怎么把域名解析成IP地址?
  6. 三星S10指纹识别玩脱了!多家金融APP关闭指纹登陆功能
  7. 大数据之-Hadoop之HDFS的API操作_文件下载案例---大数据之hadoop工作笔记0058
  8. shell for循环命令行_24 道 shell 脚本面试题
  9. 摆脱jquery,用自己的JS库实现ajax功能
  10. 【干货】js 数组操作合集(前端自我修养)
  11. c语言习题答案解析,C语言习题及答案1
  12. power oj 3149【弱水三千,只取一瓢】
  13. VCS+verdi /dve 仿真环境搭建-问题汇总
  14. 华为设备配置BGP负载分担
  15. 小知识------SATA
  16. python时间模块 datetime (datetime、timedelta和timezone部分)
  17. 苹果iOS系统下的推送机制及实现
  18. 有限自动机和右线性文法笔记
  19. android系统手机流量控制方法,如何实现Android手机流量的控制
  20. 2018 dota2 战队十杀分析

热门文章

  1. 乐学python_铁乐学python_day01-作业
  2. Oracle 一些常用函数
  3. java手机状态栏圆形图标,android实现状态栏添加图标的函数实例
  4. 数据库数据规范化看不懂_数据库管理系统中的规范化
  5. 如何让计算机两个用户使用不同步,如何实现两台或多台电脑远程修改文件同步更新?...
  6. php 文字超出画布,input实现文字超出省略号(代码示例)
  7. java中get接口示例_Java LocalDateTime类| 带示例的get()方法
  8. 更快的Maven来了,我的天,速度提升了8倍!
  9. Xamarin开发笔记—百度在线语音合成
  10. where in的sql语句按照指定ID进行排序的解决方法