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. JavaSE编程题

    Test1–取出一个字符串中字母出现的次数.如:字符串:”abcdekka27qoq”,输出格式为:a(2)b(1)k(2)… Test2–假如我们在开发一个系统时需要对员工进行建模,[员工]包含3个 ...

  2. angular的一些东西

    每个人都知道在使用angular的时候只能有一个ng-app指令但是也可以手动创建,这样就可以写很多个模块 例: var app=angular.module('App',[]);var app1=a ...

  3. java中如何使用break跳出多重循环

    java 中已知的三种跳出多重循环的方式: System.out.println("---------java中跳出多重循环的三种方式:---------"); System.ou ...

  4. 464. Can I Win

    https://leetcode.com/problems/can-i-win/description/ In the "100 game," two players take t ...

  5. Python从入门到精通之Sixth!

    补充:enumerate 函数用于遍历序列(元组tuple.列表list.字典dict)中的元素以及它们的下标: >>> for i,j in enumerate(('a','b', ...

  6. jieba库的使用和好看的词元

    一.jieba库的使用与说明 1.jieba库基本介绍 jieba库是优秀的中文分词第三方库 -中文文本需要通过分词获得单个的词语         - jieba是优秀的中文分词第三方库,需要额外安装 ...

  7. hql- 使用like的小坑①

    like '%_test_' 要把反斜杠进行转义like '%\_test\_'

  8. redis学习-列表(list)常用命令

    redis学习-列表(list)常用命令   lpush:从列表左侧头部添加数据 rpush:从右侧尾部添加数据 lpop:从给左侧头部取出一个元素 rpop:从右侧尾部取出一个元素 lrange:取 ...

  9. ehcache如何配置

    1.pom.xml文件配置(主要针对jar包的引入) <ehcache.version>2.6.9</ehcache.version><ehcache-web.versi ...

  10. 在idea中,mavne项目使用mybatis-generator-maven-plugin自动生成实体了的时候,在maven插件里面始终不显示

    最近想学习mybatis的知识,自己搭了个简单的ssm框架,想通过插件自动生成实体类,发现想要的插件一直都没显示出来,着实很郁闷: pom.xm中的配置: <!--mybatis-generat ...