微任务,宏任务,事件循环(Event Loop)

最近遇到了事件循环的问题,于是决定好好的研究一番。看了一篇文章感觉讲的特别好。

我们都知道event loop的执行顺序是:

  • 一开始整个脚本script块会做为一个宏任务执行,(宏任务)
  • 执行过程中会有一个主线程,一个宏任务队列,一个微任务队列。同步代码会按照顺序进入主线程,宏任务进入宏任务队列,微任务进入微任务队列。(微任务)
  • 当执行完主线程,主线程为空时,会优先检查微任务队列,有则依次执行,直到全部执行完微任务;
  • 执行完本轮的宏任务,再回到第2步,依次循环。

执行宏任务-->该宏任务产生的微任务,若微任务执行中产生了新的微任务,则继续执行微任务,微任务执行完毕,再回到宏任务进行下一轮循环。

后来自己也看了很多例子,但是疑惑点是,对于promise的then的微任务的微任务执行顺序是怎么样呢?

  • 例1

 

new Promise((resolve, reject) => {
    console.log("1");
    resolve();
    new Promise((resolve, reject) => {
        console.log("2");
        resolve();
    }).then(() => {
        console.log("3");
    }).then(() => {
        console.log("5");
    });
}).then(() => {
    console.log("4");
})

 输出结果是:1,2,3,4,5。答对了吗?

那我们来分析一下,是如何执行的呢:

首先,遇到Promise实例(标记为p1),执行该构造函数中的同步代码,立即执行,打印出:1;

接着,又遇到了Promise实例(标记为p2),打印出:2;

接着,p2的then为微任务,存入到微任务队列(入栈);------这里是指then后的一大坨。

接着,继续执行p1,p1的then也是微任务,存入到微任务队列(入栈);

好了,现在没有同步任务了,那我们开始对微任务队列动手了!!O(∩_∩)O

首先进去的是p2的微任务,那我们执行p2的then,打印出3;

接着,p2的后边还有then,继续存入微任务队列(入栈);

现在微任务队列执行到p1的then了,打印出4;

最后,就只剩下p1的第二个then了,继续执行,打印出5。

好啦!大家学废了吗?这里是我对promise的微任务的一些理解。接下来在看一个🌰吧!

  • 例2
console.log('start')
setTimeout(() => {
  console.log('time')
})
Promise.resolve().then(() => {
  console.log('resolve')
})
console.log('end')

输出结果为:'start' 'end' 'resolve' 'time'

分析:

  • 刚开始将整个脚本作为宏任务开始执行,遇到同步代码,打印出:start;
  • 接着,setTimeout是异步函数,作为宏任务被放到宏任务队列,入栈;
  • 依次执行到Promise.resolve().then作为一个微任务被放到微任务队列,入栈;
  • 最后执行完最后一个同步代码,打印出:end;
  • 本次宏任务的同步代码执行完,检查微任务,发现Promise.resolve().then,打印出:‘resolve’;直至微任务队列执行为空。
  • 接下来进入宏任务队列,发现setTimeout,打印出: ‘time’。
    • 接下来在看个🌰吧!
  • 例3

 

const promise = new Promise((resolve, reject) => {
  console.log(1);
  console.log(2);
});
promise.then(() => {
  console.log(3);
});
console.log(4);

 

输出结果为:1,2,4

前边看了几个例子,这个应该很easy了吧! 这里有个点就是: 为什么没有输出3呢?

-----------------因为promise实例没有状态改变啊,只有resolve才能进入then~

 

 

promise的构造函数时同步执行,promise.then中的函数是异步执行。

从全局上下文退出前,开始收集当前层级的微任务和宏任务,然后清空微任务队列,再执行宏任务。

宏任务:包括整体代码script,setTimeout,setInterval, setImmediate

 

 

 

 

微任务:

 

  • Node的Event Loop

node的事件循环是基于libuv实现的,而libuv是node的新跨平台抽象层;阶段分为6个阶段:

  1. timer:执行setTimeout,setInterval,

 ------------------------------------------------------------👇废话一箩筐  原理类内容 想看请继续------------------------------------------

事件循环

async/await  

async隐式返回promise作为结果的函数,也就是执行完await后, 立即跳出async, 执行其他代码  等到同步代码执行完毕,在去执行async剩下的代码。 吧await后边的代码注册到微任务中。

浏览器和node的  事件循环 event loop 主要区别:

两者的主要区别是浏览器的微任务是在每个相应的宏任务中执行的,而node的 微任务是在不同阶段之间执行的。

浏览器和Node的事件循环

进程是cpu资源分配的最小单位,线程是cpu资源调度的最小单位。

浏览器内核是多线程,在内核控制下各线程相互配合以保持同步,浏览器的线程组成:

GUI渲染线程,js引擎线程,定时触发器线程,事件触发线程,异步http请求线程。

  • GUI渲染线程

1、主要负责页面的渲染,解析html,css,构建dom树,布局和绘制等。

2、 当页面需要重绘或者由于某种操作引起回流,将执行该线程。

3、该线程与js引擎线程互斥,当执行js引擎线程时,GUI渲染会被挂起,当任务队列空闲时,主线程才会去执行GUI渲染。

  • js引擎线程

1、该线程主要负责处理javaScript脚本,执行代码。

2、主要负责执行准备好待执行的事件,即定时器计数结束,或者异步请求成功并正确返回时,将依次进入任务队列,等待JS引擎线程的执行。

3、因为与GUI渲染线程互斥,所以执行js引擎线程执行js脚本时间过长会引起页面堵塞。

  • 定时器触发线程

 负责执行定时器一类的函数线程,如 setTimeout  setInterval 

 主线程依次执行代码时,遇到定时器,会将定时器交给该线程处理,当计数完毕后,事件触发线程会将计数完毕的线程假如到任务队列的尾部,等待js引擎线程执行。

  • 事件触发线程

主要负责将准备好的事件交给js引擎执行。

  • 异步http请求线程

负责执行异步请求一类的函数线程。如  promise, axios, ajax

主线程依次执行代码时,遇到异步请求,会将该函数交给该线程处理,当监听到状态码变更,如果有回调函数,事件触发线程会将回调函数加入到任务队列尾部,等待js引擎线程执行。

浏览器中的event loop

宏任务: setTimeout setInterval  script  I/O操作 UI渲染

微任务: promise.then  mutationObserver

当某个宏任务执行完后,会查看是否有微任务队列。如果有,先执行微任务队列中的所有任务,如果没有,会读取宏任务队列中排在最前的任务,执行宏任务的过程中,遇到微任务,依次加入微任务队列。栈空后,再次读取微任务队列里的任务,依次类推。

node中的event  loop

Node.js的运行机制如下:

1、v8引擎解析js脚本,

2、解析后的代码,调用node api

3、libuv 库 负责node api的执行,它将不同的任务分配给不同的线程,形成event loop 。以异步的形式将任务结果返回给v8引擎。

4、v8引擎再讲结果返给用户。

 六个阶段

timer, I/O 

Node端事件循环中的异步队列也是这两种:macro(宏任务)队列和 micro(微任务)队列。

  • 常见的 macro-task 比如:setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作等。
  • 常见的 micro-task 比如: process.nextTick、new Promise().then(回调)等。

总结:

node中, 微事件是在事件循环的各个阶段执行的,process.nextTick是独立于event loop,他有自己的队列,且优于微事件执行。

浏览器中,微事件是在事件循环的宏事件执行完再执行的。

参考:

https://juejin.cn/post/6844903657264136200

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

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

https://juejin.cn/post/6844903761949753352

https://juejin.cn/post/6945319439772434469

 

posted @ 2021-07-01 12:44  阿兰儿  阅读(376)  评论(0编辑  收藏  举报