前言

各厂很喜欢考的async和await题,一般不了解他的做法都很容易踩坑。下面用三道题来讲解怎么解这类型的题目
关键词:async、await、题解

题一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0);
async1()
new Promise(resolve => {
console.log('promise1')
resolve()
})
.then(() => {
console.log('promise2')
})
console.log('script end')

第一道门槛:
大部分人在前面都没问题,到await这里就会卡住,此时对于await的情况是这样的。
他会去看自己之后的代码,

  1. 查看其中是否有同步代码,如果有,执行
  2. 如果没有 其中异步的直接放到任务栈
  3. 分析await下面的代码
    然后跳出代码,继续往下查看

其中关于await的操作,其实是

1
2
3
4
5
6
new Promise((resolve)=>{
resolve(async2());
}).then((value)=>{
console.log('async1 end')
})
//这也就是await后面的代码能看成是微任务的原因

它等待async2执行完回调这个输出

第二道门槛:
这里就来到下面看有没有同步代码了 这里就是第二步门槛,如果你认为,他直接输出’script end’,那么你就踩坑了。这里我们看到在此之前new了Promise,关键来了,他会立刻执行它的构造函数,也就是你可以把这个构造函数看成是同步代码,此时就会输出promise1.再到script end

第三道门槛:
此时,我们得知道 所有的同步任务都执行完了,开始执行任务栈中的代码了
此时的任务栈中有await之后的代码,promise的成功回调,和settimeout,当然为什么是这个顺序呢。我们要知道微任务会插队在宏任务前面,也就是一开始的顺序是

1
2
3
4
5
6
7
8
9
settimeout

await code 插队
settimeout

//遇到promise 插队在宏任务前面
await code
promise
settimeout

所以按顺序执行 结果是async1 end``promise2``setTimeout

最终答案:

题二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
new Promise(resolve => {
console.log('promise1')
resolve()
})
.then(() => {
console.log('promise2')
})
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0);
async1()
new Promise(resolve => {
console.log('promise3')
resolve()
})
.then(() => {
console.log('promise4')
})
console.log('script end')

第一道门槛:
async2中promise的构造器执行之后,将成功的回调放进任务栈,再去把await下面的code放进任务栈

任务栈的内容(异步):

1
2
3
4
5
6
7
8
9
10
11
12
13
setTimeout

promise2(插队)
setTimeout

promise2
async1 end(插队)
setTimeout

promise2
async1 end
promise4(插队)
setTimeout

最终答案

1
2
3
4
5
6
7
8
9
script start
async1 start
promise1
promise3
script end
promise2
async1 end
promise4
setTimeout

题三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
async function async1() {
console.log('async1 start')
await async2()
setTimeout(() => {
console.log('setTimeout1')
}, 0)
}
async function async2() {
setTimeout(() => {
console.log('setTimeout2')
}, 0)
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout3')
}, 0);
async1()
new Promise(resolve => {
console.log('promise1')
resolve()
})
.then(() => {
console.log('promise2')
})
console.log('script end')

前面的一样,不过这次进入async2后是宏任务,我们依然把它放进任务栈,再把
踩坑点:
容易忽视掉setimeout3是第一个宏任务。
因此答案为setimeout2 1 3 实际上是3 2 1

最终答案

1
2
3
4
5
6
7
8
script start
async1 start
promise1
script end
promise2
setTimeout3
setTimeout2
setTimeout1

总结

三道基本的题,掌握了await的基本原理。其实就是promise的回调。