【CRR学习笔记】JavaScript之Event Loop

216 阅读3分钟

Event Loop

前言

如果不知道js中的event loop,在代码中出现setTimeout,Promise,甚至复杂的链式调用时,你写的代码在何时执行,执行顺序如何,你就会陷入混乱。

我的总结

在Js中有个StackQueue,在第一次执行主代码段时,console.log,setTimeout,Promise等会根据从上到下的顺序依次进入StackQueue,每次进入时会判断它是同步任务还是异步任务,若是同步任务那么立马执行,比如console.log,new Promise里面的代码,当然执行的是里面的同步任务。 若是异步任务,会根据其是macrotask,还是microtask来将其加入宏任务队列,和微任务队列。比如promise的then回调函数会被加入microtask队列,而setTimeout的执行代码段会被加入macrotask队列。

主代码段执行完毕后,会将微任务队列的代码全部执行完毕,若产生其他微任务也会加在队列末尾,这一个回合执行完毕。

接着执行宏任务队列最前面的一条任务,若在执行过程中产生微任务则加入微任务队列。

执行微任务队列,再执行一条宏任务,如此往复。 宏队列,macrotask,也叫tasks。 一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:

setTimeout setInterval setImmediate (Node独有) requestAnimationFrame (浏览器独有) I/O UI rendering (浏览器独有)

微队列,microtask,也叫jobs。 另一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:

process.nextTick (Node独有) Promise Object.observe MutationObserver

(注:这里只针对浏览器和NodeJS)

举个栗子:

console.log(1); //同步任务 

setTimeout(() => { //异步任务 callback1
  console.log(2); 
  Promise.resolve().then(() => { //callback2
    console.log(3); 
  });
});

new Promise((resolve, reject) => { //同步任务
  console.log(4)
  resolve(5)
}).then((data) => { //异步任务 microtask callback3
  console.log(data);
  
  Promise.resolve().then(() => {  //异步任务 microtask callback4
    console.log(6)
  }).then(() => {
    console.log(7) //callback6
    
    setTimeout(() => { // 异步任务 macrotask 
      console.log(8) callback7
    }, 0);
  });
})

setTimeout(() => { //异步任务:macrotask
  console.log(9); //callback5
})

console.log(10); //同步任务

具体过程如下:

  1. 首先执行主代码段,将事件依次加入队列
StackQueue 任务
1 console
2 setTimeout
3 new Promise
4 setTimeout
5 console

在这个任务栈中,同步任务依次执行,输出:1 4 10

在压栈的过程中,macrotask队列,microtask队列也有了内容。

macrotask 任务
1 callback1
2 callback5
microtask 任务
1 callback3

先把微任务队列的任务清空: 输出:5

产生新的微任务,继续执行,输出:6

microtask 任务
1 callback4

又产生新的微任务,继续执行,输出:7

microtask 任务
1 callback6

执行栈压入:setTimeout 宏任务栈压入:

macrotask 任务
1 callback1
2 callback5
3 callback7

此时,微任务队列清空,开始执行宏任务队列第一条任务callback1,输出:2,同时在微任务队列压入新的任务

microtask 任务
1 callback2

执行微任务队列,输出:3 再次执行宏任务队列最顶端的任务callback5,输出:9 微任务队列为空,继续执行宏任务callback7,输出:8

所以这一段代码完整的输出顺序是:

1
4
10
---
5
6
7
---
2
3
---
9
8

这么一描述你明白了吗??

参考文献

juejin.cn/post/684490…