Event loop

复习一下之前看过Event loop

 首先说一下为啥有这个东西.

   因为JavaScript是单线程的,也就是只能顺序执行,当时当我们某一个点需要的等待的时间比较长的时候,那我们的页面就会卡顿,下面的逻辑以及处理也都会进行等待,这个时候就有了Event loop的加入,

js为什么是单线程的?

  通俗一点来讲就是:js更多的是和用户进行交互,那如果再一个计划没有执行完,再次执行了下一个计划,而第二个计划又依赖与第一个计划的时候,那我们的页面就会出现问题,给用户不完美的体验

有了它(Event loop)我们能做什么?

    举个例子:当我们去请求数据的时候,犹豫后台反应慢或者数据大,那我们再请求的时候所花费的时间就会比较长,那我们再请求的时候能做其它的吗?答案当然是可以了,借用之前以为大佬说过的话,没有代码实现不了的,有,就是你接触的还不够深.  

  Javascript是单线程的,单线程就意味着所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

如果其中一个任务很慢,占用了很多的时间,此时网页就可能卡住

有些 I/O (输入输出) 操作是很慢的,比如 Ajax 操作从网络读取数据

JS 语言的设计者意识到,主线程可以不管这些 I / O 操作,把等待中的任务挂起,先运行排在后面的任务。等待 I / O 操作返回结果,再去执行挂起的任务

因此任务可以分为两种,一种是同步任务,一种是异步任务

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务

异步任务指的是,不进入主线程,而是进入任务队列,通过 Event Loop 机制等待合适的时间调用

有了 Event Loop 的加持,JS 才能非阻塞地运行

以上是js的Event loop,

那么浏览器是否有自己的Event loop呢?答案也是有的,

浏览器的Event loop

首先看一张图

先别被这张图吓坏,看看执行一个 JavaScript 代码的具体流程

  1. 执行全局 Script 代码,这些代码中有同步语句或异步语句,遇到同步语句直接执行,异步语句放入宏任务或微任务的队列。
  2. 全局 Script 代码执行完毕后,调用栈 Stack 会清空
  3. 从微任务中取出位于队首的回调任务,放入调用栈 Stack 中执行,执行完成后 微任务队列长度减一
  4. 继续取出位于队首的任务,放入调用栈 Stack 中执行,以此类推,直到把 微任务队列 中的所有任务都执行完毕。注意,如果在执行微任务过程中,又产生了新的微任务,那么会加入到微任务队列的尾部,也会在这个周期被执行
  5. 当 微任务队列 中的所有任务都执行完毕后,此时 微任务队列 为空,调用栈 Stack 也会空
  6. 取出宏任务中的队首的任务放入 Stack 中执行
  7. 执行完毕后,调用栈Stack为空
  8. 重复第3-7个步骤
  9. 重复第3-7个步骤
  10. ...

可以看到,这就是浏览器的事件循环 Event Loop

这里归纳3个重点:

  1. 宏任务一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务;
  2. 微任务队列中所有的任务都会被依次取出来执行,直到 微任务队列 为空;
  3. 图中没有画UI rendering的节点,因为这个是由浏览器自行判断决定的,但是只要执行UI rendering,它的节点是在执行完所有的 微任务 之后,下一个 宏任务 之前,紧跟着执行UI render。

下面看一下小例子:

console.log(1);

setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
});

new Promise((resolve, reject) => {
  resolve(4)
}).then((data) => {
  console.log(data);
})

setTimeout(() => {
  console.log(5);
})

console.log(6);

以上建议先自己看一下,然后再看答案,

以上执行顺序: 

console.log(1);这个应该是没有疑问的吧,第一个执行,它再最顶端  并且是属于微任务的.
然后呢碰到了
setTimeout;这个属于宏任务,滚到一边去
接下来是new Promise;这个属于微任务里面没有微任务,加入队列
new Promise().then属于宏任务,滚到一边
setTimeout属于宏任务,滚到一边
console.log(6);微任务  立即执行
到这里所有的微任务执行完毕,开始执行宏任务
拿到第一个setTimeout,里面有微任务,执行,微任务执行完执行宏任务
然后只剩下一个
setTimeout


最后执行顺序:1.6.4.2.3.5


总结:

  1. JavaScript 是单线程的,有了 Event Loop 的加持,JS 才可以非阻塞地执行
  2. 浏览器的 Event Loop 机制,分为 宏任务 和 微任务
  3. 微任务比宏任务优先级高,事件循环开始后,微任务首先执行,直到微任务队列清空,然后执行宏任务队列,如果宏任务队列执行过程中,产生了新的微任务,需要立刻执行微任务,直到微任务队列清空,然继续执行宏任务,直到宏任务队列清空
  4. 宏任务: setTimeout、setInterval、requestAnimation(浏览器)、IO、UI rendering
  5. 微任务: process.nextTick(Node)、Promise、Object.observe、MutationObserver
原文地址:https://www.cnblogs.com/wgs-blog/p/14977352.html