题目
先看个例题吧。如下:
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后面的内容,会当成一个微任务。
现在程序的执行状态:
已打印:4、1、3
宏任务队列:(14-20)、(24)
微任务队列:(4)
- 再看29-34,new Promise里面的内容会立刻执行。但是.then里面的内容会被推入到微任务队列
现在程序的执行状态:
已打印:4、1、3、9
宏任务队列:(14-20)、(24)
微任务队列:(4)、(33)
- 在看后面还有个36行,直接打印把。
现在程序的执行状态:
已打印:4、1、3、9、11
宏任务队列:(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
后记
就是对实际代码中遇到的宏任务,微任务等内容的解析。如果有任何疑问,可以留言交流。如果本文对你有帮助,就帮我点赞+关注吧,谢谢大家。