event loop 即事件循环。最初了解到js的event loop机制是通过自己对js中异步、同步的疑惑。今天聊一聊自己的理解,希望和大家一起学习。

首先,让我们看一个经典的setTimeOut的问题

console.log(1)
setTimeOut(function(){
console.log(2)
},1000)
setTimeOut(function(){
console.log(3)
},0)
console.log(4)

  

  浏览器打印的结果是怎样的呢?大家可以写一段脚本试一下,打印的结果是1,4,3,2;为什么不是按照js从上到下的执行顺序,输出1,3,4,2呢?这就要说到我们今天的主题,js的事件循环机制了。

  想要了解event loop我们就要从js的工作原理说起。首先,大家都知道js是单线程的。所谓单线程就是进程中只有一个线程在运行。那么,js为什么是单线程而不是做成多线程的呢?个人理解,js是用来实现浏览器与用户之间的交互的。如果同时要处理用户点击,用户输入,用户关闭等操作,浏览器无法知道这个时间我到底应该做什么。所以js是从上至下按顺序运行下去的。这里谈及到两个名词,线程和进程。简单介绍:进程,可以理解为正在运行的程序的实体。例如,在手机中打开一个app,打开了一个后台进程。那么,线程又是什么呢?线程是程序执行流的最小单位,也叫轻量级的进程。是程序执行的过程中,一个单一的顺序控制流程。一个进程中,包含很多的线程。单线程,程序执行的过程中,所走的程序路径按照连续的顺序排下来。前面的必须处理好,后面的才会执行。

  按照单线程的思想,顺序执行我们的代码,那么,如果我们的js中间向后台发送一个ajax请求,就要等到请求等到结果后才会继续向下执行。如果请求耗时10秒,页面就要停在这里10秒。这样的用户体验很不好。。。因此,就有了同步任务、异步任务的区别。所谓异步任务,就好比我们在烧水的同时看书,等到水烧好了,再用烧好的水煮面。这就是一个简单的异步操作。异步可以提高处理事件的效率。异步任务就可以解决单线程按照顺序依次执行,不可以同时进行多个任务的问题。

  同步任务和异步任务在js中是如何执行的呢?js的代码运行会形成一个主线程和一个任务队列。主线程会从上到下一步步执行我们的js代码,形成一个执行栈。同步任务就会被放到这个执行栈中依次执行。而异步任务被放入到任务队列中执行,执行完就会在任务队列中打一个标记,形成一个对应的事件。当执行栈中的任务全部运行完毕,js会去提取并执行任务队列中的事件。这个过程是循环进行的,这就是我们今天想要了解的event loop。

  这里简单粗暴的理解一下异步任务,什么样的任务会被放到任务队列中呢?简单理解,有callback函数的就可以被看做是异步任务,会被放到任务队列中执行。大家可能在使用vue的时候用到过$nextTick方法,这个方法的主要目的就是把事件直接插入到执行栈的最后,而不是放入到任务队列中去执行。这个执行流程就变成了执行栈的任务——>$nextTick——>任务队列。

  我们回过头再来看一下最开始提到的问题。console.log(1)和console.log(4)在主线程的执行栈中执行完,此时,执行栈被清空,js开始执行任务队列中的两个setTimeOut事件。先执行延迟时间设置为0秒的setTimeOut打印出3,再执行1秒的setTimeOut事件,打印出2。最后的输出结果就是1、4、3、

因为js的event loop机制,所以大家不要认为setTimeOut设置的事件到了延迟时间就是被执行。如果你的执行栈任务没有被全部执行完,清空。setTimeOut事件执行的时间很有可能是要大于你设置的延时参数。

通过了解js的实现基础和它的执行顺序,进一步让我理解里eventloop的工作原理。脑子里有了一个执行机制的大概流程。通过开头的setTimeout引出了事件循环的概念,随着ES6的广泛应用。同样解决异步问题的Promise对象,可以通过它的链式写法,达到写同步代码的手法实现异步任务的效果。那么,Promise和setTimeout在事件队列里是否一样呢?

console.log(1);

setTimeout(function() {
console.log(2);
}, 0); Promise.resolve().then(function() {
console.log(3);
}).then(function() {
console.log(4);
}); console.log(5);

这段js执行的结果是1,5,2,3,4么?大家可以尝试一下。根据上面得到的结论,首先输出的应该是1,5,因为console.log(1)和console.log(5)是执行栈里的同步任务,完成后才进行事件循环。那么setTimeout和Promise的执行顺序是怎样的呢?

这里就要引入两个新名词,microtask、macrotask。即宏任务和微任务。

宏任务: 需要多次事件循环才能执行完,事件队列中的每一个事件都是一个宏任务。浏览器为了能够使得js内部宏任务与DOM任务有序的执行,会在一个宏任务执行结束后,在下一个宏执行开始前,对页面进行重新渲染 (task->渲染->task->…)鼠标点击会触发一个事件回调,需要执行一个宏任务,然后解析HTML。setTimeout的作用是等待给定的时间后为它的回调产生一个新的宏任务。

微任务: 微任务是一次性执行完的。微任务通常来说是需要在当前task执行结束后立即执行的任务,例如对一些动作做出反馈或者异步执行任务又不需要分配一个新的task,这样便可以提高一些性能。只要执行栈中没有其他的js代码正在执行了,而且每个宏任务都执行完了,微任务队列会立即执行。如果在微任务执行期间微任务队列加入了新的微任务,会将新的微任务加入队列尾部,之后也会被执行。简单理解,宏任务在下一轮事件循环执行,微任务在本轮事件循环的所有任务结束后执行。

宏任务主要包括了:setTimeout、setInterval、setImmediate、I/O、各种事件(比如鼠标单击事件)的回调函数

优先级:主代码块 > setImmediate > MessageChannel > setTimeout / setInterval

微任务主要包括了:process.nextTick、Promise、MutationObserver

优先级:process.nextTick > Promise > MutationObserver

看到这里,想必大家已经得到了上面代码块的执行结果。对于事件循环机制粗浅的介绍到这里,希望能帮助到大家。如果文中哪里阐述有问题,还请各位大神多多指点。


关于事件队列,之前大转转FE也写过一篇,和本文角度不同,感兴趣的同学可以看看 浏览器内事件队列

Event Loop浅谈的更多相关文章

  1. 从Event Loop谈JS的运行机制

    这里主要是结合Event Loop来谈JS代码是如何运行的. 事件循环对于我们平时开发可以说是特别重要,可以让我们写出更好的代码. 到这里相信我们已经知道了JS引擎是单线程,而且这里会用到前面说的的几 ...

  2. 浅谈 Event loop (事件循环)

    从Event Loop谈JS的运行机制 先来理解一个概念: JS分为同步任务和异步任务 同步任务都在主线程上执行,形成一个执行栈 Execute Content Stack 主线程之外,事件触发线程管 ...

  3. JavaScript 运行机制详解:再谈Event Loop

    原文地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Eve ...

  4. javascript运行机制详解: 再谈Event Loop(转)

    作者: 阮一峰 日期: 2014年10月 8日 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Event Loop的理解. 上个月,我偶然看到了Philip Roberts ...

  5. 【repost】JavaScript 运行机制详解:再谈Event Loop

    一年前,我写了一篇<什么是 Event Loop?>,谈了我对Event Loop的理解. 上个月,我偶然看到了Philip Roberts的演讲<Help, I'm stuck i ...

  6. [转载]JavaScript 运行机制详解:再谈Event Loop

    https://app.yinxiang.com/shard/s8/sh/b72fe246-a89d-434b-85f0-a36420849b84/59bad790bdcf6b0a66b8b93d5e ...

  7. 【朴灵评注】JavaScript 运行机制详解:再谈Event Loop

    PS: 我先旁观下大师们的讨论,得多看书了~   别人说的:“看了一下不觉得评注对到哪里去,只有吹毛求疵之感. 比如同步异步介绍,本来就无大错:比如node图里面的OS operation,推敲一下就 ...

  8. 从Javascript单线程谈Event Loop

    假如面试回答js的运行机制时,你可能说出这么一段话:"Javascript的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后 ...

  9. 深入理解Javascript单线程谈Event Loop

    假如面试回答js的运行机制时,你可能说出这么一段话:"Javascript的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后 ...

随机推荐

  1. HTML 中使用 JavaScript

    在 HTML 中插入 JavaScript 的主要方法,就是使用 <script> 元素, 浏览器会解释并执行其中的 JavaScript 代码. <script>  元素的属 ...

  2. P4149 [IOI2011]Race

    对于这道题,明显是点分治,权值等于k,可以用桶统计树上路径(但注意要清空); 对于每颗子树,先与之前的子树拼k,再更新桶,维护t["len"]最小边数; #include < ...

  3. C#中get和set属性的作用

    c#在定义类时,通常要把类中声明的对象封装起来,使得外界不能访问这个属性.上述代码中如果去掉set部分,则外界只能读取name的值,如果去掉get部分,则只能给name赋值.这样就可以控制外界对私有属 ...

  4. rem 原理与简介

    一.rem 原理与简介 字体单位:     值根据 html 根元素大小而定,同样可以作为宽度,高度等单位 适配原理:     将 px 替换为 rem,动态修改 HTML 根元素的 font-siz ...

  5. Apple Mach-O Linker Error Group 与 "_OBJC_CLASS_$_XXXXXX", referenced from: 和 clang: error: linker command failed with exit code 1 (use -v to see invocation) 问题.

    此问题为链接报错,在Build Settings中的Other Linker Flags添加:-l"XXXXXX"

  6. 走进JDK(十一)------LinkedHashMap

    概述LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,LinkedHas ...

  7. [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析

    String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识,  ...

  8. windows安装zookeeper

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...

  9. ubuntu installs matlab2017a

    cd mkdir matlab sudo mount -o loop *1.iso matlab sudo ./matlab/install ... sudo mount -o loop *2.iso ...

  10. python猜数字游戏console版本

    加入python学习小组后的第一次作业,python GUI写猜数字游戏.由于加班比较多,第一步先实现console版本,下一步再实现GUI版本. 虽然猜数字游戏是个小游戏,但是涉及到的基础知识点还是 ...