通过案例学习 宏任务,微任务,Promise

243 阅读5分钟

题目

先看个例题吧。如下:

1 async function async1 () {
2  console.log(1)
3  await async2()
4  console.log(2)
5 }
6
7 async function async2 () {
8  console.log(3)
9 }
10 
11 console.log(4)
12
13 setTimeout(function () {
14  console.log(5)
15  new Promise(function (resolve) {
16    console.log(6)
17    resolve()
18  }).then(function () {
19    console.log(7)
20  })
21 })
22
23 setTimeout(() => {
24  console.log(8)
25 }, 0)
26
27 async1()
28
29 new Promise(function (resolve) {
30  console.log(9)
31  resolve()
32 }).then(function () {
33  console.log(10)
34 })
35
36 console.log(11)

知识点

那么这道题到底考察什么知识点呢?

  • 宏任务 微任务

浏览器里的事件循环机制,js在执行的过程中,会维持一个宏任务队列,一个微任务队列。执行顺序: (1),一个宏任务 (2),所有微任务 (3),下一个宏任务,所有微任务,也就是重复执行1,2

那么哪些语句会产生宏任务或者微任务呢?

async/await

async/await本质上还是基于Promise的一些封装,而Promise是属于微任务的一种。所以在使用await关键字与Promise.then相同。
async函数在await之前的代码都是同步执行的,可以理解为await之前的代码属于new Promise时传入的代码, await之后的所有代码都是在Promise.then中的回调。

settimeout

宏任务

promise.then

微任务 注意:一定是.then里面的内容会被当成微任务处理,在.then之前的Promise里,当成参数传入的函数里面的内容,是正常执行的。

解题思路

我想一步一步详细的介绍一下这个程序的执行过程。大家可以相邻步骤依依对比,来理解具体的执行过程。

说明: 我们用小括号表示一个任务。比如:

(1-3)

表示一个任务,需要执行第1-3行的代码。

  • 从第1行到34行,先把主线程里的代码执行完。如果遇到某些代码产生了宏任务或者微任务,将其推入宏任务或微任务的队列。
现在程序的执行状态:
已打印:
宏任务队列:
微任务队列:
  • 第一行到第第10行只定义了函数,并没有执行,所以我们先跳过。
  • 11 行有一个打印语句,会先执行,那么会输出4
现在程序的执行状态:
已打印:4
宏任务队列:
微任务队列:
  • 13 - 21 这里是一个settimeout,但是没有延迟时间,我们可以认为延迟时间是0。这是一个宏任务。
现在程序的执行状态:
已打印:4
宏任务队列:(14-20)
微任务队列:
  • 继续往后执行,23-25 是一个settimeout。会产生一个宏任务,我们推入宏任务队列。
现在程序的执行状态:
已打印:4
宏任务队列:(14-20)、(24)
  • 27 这里是一个async函数。我们找到function async1里面的内容。先打印1。
现在程序的执行状态:
已打印:4、1
宏任务队列:(14-20)、(24)
  • 然后发现里面有await 函数,await里面的内容会立刻执行,但是await后面的内容,会当成一个微任务。
现在程序的执行状态:

已打印:413

宏任务队列:(14-20)、(24)

微任务队列:(4)
  • 再看29-34,new Promise里面的内容会立刻执行。但是.then里面的内容会被推入到微任务队列
现在程序的执行状态:

已打印:4139

宏任务队列:(14-20)、(24)

微任务队列:(4)、(33
  • 在看后面还有个36行,直接打印把。
现在程序的执行状态:

已打印:413911

宏任务队列:(14-20)、(24)

微任务队列:(4)、(33
  • 主线程已经当成一个宏任务执行完毕了。现在取出所有微任务去执行吧。
  • 执行微任务(4)
现在程序的执行状态:

已打印:4、1、3、9、11、2

宏任务队列:(14-20)、(24)

微任务队列:(33)
  • 执行微任务 (33)
现在程序的执行状态:

已打印:4、1、3、9、11、2、10

宏任务队列:(14-20)、(24)
微任务队列: 空

现在微任务队列被清空了。我们接下来要执行下一个宏任务了。

  • 执行宏任务(14-20) 同理 14、16行会立刻执行。但是19处于.then里面。被当成微任务,推入微任务队列。
现在程序的执行状态:

已打印:4、1、3、9、11、2、10、5、6

宏任务队列:(24)
微任务队列:(19)
  • 现在又到了把所有微任务清空的时候了。执行19行。
现在程序的执行状态:

已打印:4、1、3、9、11、2、10、5、6、7

宏任务队列:(24)
微任务队列: 空
  • 现在又要执行下一个宏任务(24),直接打印8了。
现在程序的执行状态:

已打印:4、1、3、9、11、2、10、5、6、7、8

宏任务队列:空
微任务队列:空
  • 到这一步为止,宏任务和微任务队列都已经执行完毕了。最后的结果就是:
4、1、3、9、11、2、10、5、6、7、8

后记

就是对实际代码中遇到的宏任务,微任务等内容的解析。如果有任何疑问,可以留言交流。如果本文对你有帮助,就帮我点赞+关注吧,谢谢大家。