说事件循环(event loop)之前先要搞清楚几个问题。

1. js为什么是单线程的?
  试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的?
 
2.js为什么需要异步?
  如果js不是异步的话,由于js代码本身是自上而下执行的,那么如果上一行代码需要执行很久,下面的代码就会被阻塞,对用户来说,就是”卡死”,这样的话,会造成很差的用户体验。
 
3.js是如何实现异步的?
  既然js是单线程的,那么js是如何实现异步的呢,是通过事件循环(event loop),理解了event loop 就理解了js的执行机制。
 
4.浏览器中的多线程?
  js是单线程的,但是浏览器是多线程的,多个线程相互配合以保持同步,浏览器下的线程有
  • JavaScript引擎线程,用于解析JavaScript代码
  • GUI渲染线程,(它与javaScript线程是互斥的)
  • 事件线程(onclick,onchange,…)
  • 定时器线程(setTimeout, setInterval)
  • 异步http线程(ajax),负责数据请求
  • EventLoop轮询处理线程,事件被触发时该线程会把事件添加到待处理队列的队尾
 
说道浏览器的多线程,我们可以说一下,主线程和异步线程之间是怎么配合的:主线程发起一个异步请求(比如http请求),相应的工作线程接收请求并告知主线程已收到通知(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作之后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数);
 
5. javaScript 的事件循环(event loop)
既然js是单线程的,那么所有的任务就需要排队执行。
  • javaScript 中的任务可以被划分为宏任务(Macrotask)或者微任务(Microtask)
  • 像鼠标事件,键盘事件,"ajax","setTimeout"等就属于宏任务,需要注意的是,主线程的整体代码(script标签),也是一个宏任务
  • process.nextTick,PromiseA.then(), MutaionObserver 就属于微任务
简单概括一下事件循环,就是
1.执行宏任务队列中第一个任务,执行完后移除它
2.执行所有的微任务,执行完后移除它们
3.执行下一轮宏任务(重复步骤2)
如此循环就形成了event loop,其中,每轮执行一个宏任务和所有的微任务
 
下图很形象的描述了event loop

网上有用异步任务和同步任务来说明这个问题的,但是我觉得用宏任务和微任务更好点。

 
下面我通过分析一个示例来说一下:
console.log(1);

setTimeout(function(){
console.log(2)
},10); new Promise(function(resolve){
console.log(3)
for( var i=100000 ; i>0 ; i-- ){
i==1 && resolve()
}
console.log(4)
}).then(function(){
console.log(5)
}).then(function(){
console.log(6)
}) console.log(7);

打印出来的结果是:1 3 4 7 5 6 2

我们分析一下整个过程

1. 首先执行主线程这个宏任务,从上到下执行,遇到console.log(1); 打印1出来

2. 遇到setTimeout,把它丢给定时器线程处理,然后继续往下执行,并不会阻塞10毫秒,而此处定时器线程会在,主线程执行完后的10毫秒,把回调函数放入宏任务队列。

3. 遇到new Promise,直接执行,先打印 ‘3‘ 出来,然后执行for循环,达到条件之后,把promise的状态改为resolved,继续执行打印 ‘4’ 出来

4.遇到promise的then, 属于微任务,则把回调函数放入微任务队列

5.又遇到promise的then, 属于微任务,则把回调函数放入微任务队列

6. 遇到console.log(7) 打印 ‘7’ 出来

7. 宏任务执行完后会执行所有待执行的微任务,所以会相继打印 ‘6’, ‘7’ 出来。

至此第一轮循环已经结束了,第一轮循环里的宏任务和微任务都会被移除出任务队列,接下来开启第二轮循环,

1.首先查找是否有宏任务,由于setTimeout 的回调被放入了宏任务队列,这里会执行回调函数的代码,打印了 ‘2’ 出来

2. 接着查找是否有微任务,发现没有微任务,则本轮循环结束

接下来会重复上面的步骤,这就是event loop 了。后续当我们触发点击事件,有回调函数的话,回调函数也会被放入宏任务队列,一旦队列里重新有了任务,就会被执行。

6. 扩展题目

如果能把上面这道题的流程说清楚,那么恭喜你,对event loop理解的不错了。 下面我们再利用上面的题目扩展一下,加深理解。

下面的代码打印出来的结果是什么?

console.log(1);

setTimeout(function(){
new Promise(function(resolve){
console.log('promise in setTimeout1');
resolve();
}).then(function(){
console.log('then in setTimeout1');
})
},10); new Promise(function(resolve){
console.log(3);
for( var i=100000 ; i>0 ; i-- ){
i==1 && resolve();
}
console.log(4)
}).then(function(){
console.log(5);
}); setTimeout(function(){
console.log('setTimeout2');
},10); console.log(7);

结果如下:

可以发现,第二个setTimeout 的回调函数,执行的比第一个setTimeout里面的promise.then()的回调要晚,这是因为每次循环只执行一个宏任务,但是却会执行所有待执行的微任务,而第二个setTimeout在宏任务队列的位置在第一个setTimeout后面。

这个就是我理解的JavaScipt 事件循环机制,参考了很多文章,也自己做了很多思考写出来的,码字不易,觉得有帮助可以点个赞哦。也欢迎留言交流

参考文章

https://segmentfault.com/a/1190000012806637?utm_source=tag-newest

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

https://zhuanlan.zhihu.com/p/33127885

https://zhuanlan.zhihu.com/p/33136054

https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context

 

JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念的更多相关文章

  1. 简单了解一下事件循环(Event Loop)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  2. JS事件循环(Event Loop)机制

    前言 众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言. 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选 ...

  3. 事件循环 event loop 究竟是什么

    事件循环 event loop 究竟是什么 一些概念 浏览器运行时是多进程,从任务管理器或者活动监视器上可以验证. 打开新标签页和增加一个插件都会增加一个进程,如下图:  浏览器渲染进程是多线程,包 ...

  4. 事件循环Event loop到底是什么

    摘要:本文通过结合官方文档MDN和其他博客深入解析浏览器的事件循环机制,而NodeJS有另一套事件循环机制,不在本文讨论范围中.process.nextTick和setImmediate是NodeJS ...

  5. 浏览器与Node的事件循环(Event Loop)有何区别?

    前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的. 一.线程与进程 1. 概念 我们经常说 JS 是单线程执行的,指的是一个进程里 ...

  6. JavaScript事件循环(Event Loop)机制

    JavaScript 是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决定 ...

  7. JavaScript 事件循环 — event loop

    引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...

  8. 一文梳理JavaScript 事件循环(Event Loop)

    事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个 ...

  9. 事件循环Event Loop

    在 事件循环 期间的某个时刻,运行时会从最先进入队列的消息开始处理队列中的消息.被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数.正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧. ...

随机推荐

  1. JavaSE习题 继承接口和泛型

    问答题: 1.子类在什么情况下可以继承父类友好成员? 答:在同一个包内 2.子类通过怎样的方法可以隐藏继承的成员变量? 答:声明一个与父类相同变量名的成员变量 3.子类重写继承的方法原则是什么? 答: ...

  2. django会话session

    因为因特网HTTP协议的特性,每一次来自于用户浏览器的请求(request)都是无状态的.独立的.通俗地说,就是无法保存用户状态,后台服务器根本就不知道当前请求和以前及以后请求是否来自同一用户.对于静 ...

  3. 文件编码检测.ZC

    1.今天(20181101) 发现 g文件中的 xml头 和 文件编码不一致,最后发现 貌似是我搞错了,人家的文件 编码方式写的是对的. 我发现的现象是:XML里面写的是"GBK" ...

  4. HttpClient的POST请求返回302解决

    HttpClient请求POST提示302,而且返回的response中的Localtion是我访问时使用的URL, 例如:我使用的URL是https://bbs.csdn.net?client_id ...

  5. 虹软2.0 免费人脸识别C#类库分享

    目前只封装了人脸检测部分的类库,供大家交流学习,肯定有问题,希望大家在阅读使用的时候及时反馈,谢谢!使用虹软技术开发完成 戳这里下载SDKgithub:https://github.com/dayAn ...

  6. MySQL学习(七)

    学习子查询 1 查出本网站最新的good_id最大的一条商品(要求取出商品名) mysql> select goos_id,goods_name from goods -> order b ...

  7. angular 拦截器

    介绍:$http service在Angular中用于简化与后台的交互过程,其本质上使用XMLHttpRequest或JSONP进行与后台的数据交互.在与后台的交互过程中,可能会对每条请求发送到Ser ...

  8. Axure 设置条件的操作

    登录的三种场景: 1.用户名为空,只输入密码时,执行三个动作:跳出提示内容(用户名为空).光标定位在用户名的文本框中.清空密码的文本框: 2.密码为空,只输入用户名,执行两个操作:跳出提示内容(密码为 ...

  9. 雷林鹏分享:jQuery EasyUI 树形菜单 - 树形菜单拖放控制

    jQuery EasyUI 树形菜单 - 树形菜单拖放控制 当在一个应用中使用树(Tree)插件,拖拽(drag)和放置(drop)功能要求允许用户改变节点位置.启用拖拽(drag)和放置(drop) ...

  10. 8.2 DRAM和SRAM

    计算机组成 8 存储层次结构 8.2 DRAM和SRAM SRAM比较快,DRAM比较慢:SRAM比较贵,DRAM比较便宜.记住这些结论是很容易的,但是比是什么更重要的是为什么.那在这一节我们就从电路 ...