简述事件循环(event loop)、微任务、宏任务

首先明白以下几点:

JS为什么是单线程的?

js作为主要运行在浏览器的脚本语言,js主要用途之一是操作DOM。假如有两个线程,多线程的JS对同一个dom操作,一个发出删除,一个发出编辑,这时候浏览器究竟该如何执行呢?

JS为什么需要异步?

如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验

JS单线程又是如何实现异步的呢?

既然JS是单线程的,只能在一条线程上执行,又是如何实现的异步呢? 是通过的事件循环(event loop),理解了event loop机制,就理解了JS的执行机制

浏览器的多线程

  • GUI 渲染线程 (负责渲染浏览器界面HTML元素)
  • JavaScript引擎线程(主要负责处理Javascript脚本程序,例如V8引擎,GUI渲染线程和JavaScript引擎线程互斥!)
  • 事件触发线程(如鼠标点击、AJAX异步请求等)
  • 定时触发器线程( setTimeout, setInterval )
  • 异步http请求线程
  • 事件轮询处理线程 ( 作用:轮询消息队列,event loop )

说到浏览器的多线程,我们可以说一下,主线程和异步线程之间是怎么配合的:主线程发起一个异步请求(比如http请求),相应的工作线程接收请求并告知主线程已收到通知(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作之后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数);

javaScript 的事件循环(event loop)

因为js是单线程 所以所有的任务都要排队执行,任务分为两种:宏任务、微任务

宏任务

script(整体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)

微任务

Promise、 MutaionObserver、process.nextTick(Node.js环境)

事件循环流程

  1. 执行宏任务队列中第一个任务,执行完后移除它
  2. 执行所有的微任务,执行完后移除它们
  3. 执行下一轮宏任务(重复步骤2)

宏任务 > 所有微任务 > 宏任务 如此循环就形成了event loop,其中,每轮执行 一个宏任务 和所有的微任务

事件循环图示

在这里插入图片描述

扫描二维码关注公众号,回复: 8854153 查看本文章

示例

	console.log(1)
    setTimeout(function () {
        console.log(2);
    });
    new Promise(function(resolve,reject){
        console.log(3)
        resolve(4)
    }).then(function(val){
        console.log(val);
    })
    console.log(5);

打印的结果是:1 3 5 4 2
解析:

  1. 首先执行主线程这个宏任务,从上到下执行,遇到console.log(1); 打印1出来
  2. 遇到setTimeout,把它丢给定时器线程处理,然后继续往下执行,并不会阻塞定时器,而此处定时器线程会在,主线程执行完后,把回调函数放入宏任务队列。
  3. 遇到new Promise,直接执行,先打印 ‘3‘ 出来
  4. 遇到promise的then, 属于微任务,则把回调函数放入微任务队列
  5. 遇到console.log(5) 打印 ‘5’ 出来
  6. 宏任务执行完后会执行所有待执行的微任务,所以会相继打印 ‘4’ 出来。

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

  1. 首先查找是否有宏任务,由于setTimeout 的回调被放入了宏任务队列,这里会执行回调函数的代码,打印了 ‘2’ 出来
  2. 接着查找是否有微任务,发现没有微任务,则本轮循环结束

接下来会重复上面的步骤,这就是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后面。








本文参考了好多大牛解析 感谢观看 欢迎交流~

发布了1 篇原创文章 · 获赞 0 · 访问量 172

猜你喜欢

转载自blog.csdn.net/qq_39539687/article/details/100557701