这道题主要是考察这三者在事件循环中的区别,事件循环中分为宏任务队列和微任务队列。
- setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行;
- Promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行;
- async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。
练习题
题目1
async function fn1() {
console.log(1);
const result = await fn2();
console.log(2);
}
async function fn2() {
console.log(3);
return new Promise((resolve, reject) => {
resolve(); // 如果这里不执行resolve,那么将输出1 3 6 5
}).then(() => {
console.log(4)
});
}
Promise.resolve().then(() => {
console.log(5)
});
fn1();
console.log(6);
// 输出结果:1 3 6 5 4 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
需要注意以下几点:
- await只能在async函数中使用。
- await后面可以跟普通的函数,也可以跟带有then方法的对象,也就是thenable。
- 如果后面跟的是thenable时,await会收集thenable对象的原型对象上的then方法,并给其注入resolve和reject;然后阻塞当前作用域代码的执行,等待注入的resolve开启微任务异步队列的执行。如果后面不是thenable对象的话,直接开启微任务异步队列的执行。
题目2
async function async1() {
console.log(1)
const result = await async2();
console.log(3)
}
async function async2() {
console.log(2);
}
Promise.resolve().then(() => {
console.log(4)
})
setTimeout(() => {
console.log(5)
})
async1();
console.log(6);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
结果如下:1 2 6 4 3 5
分析:这道题涉及到的基本原理有以下几个方面:
- 同步异步
- 宏任务和微任务原理
- promise原理
- async-await原理
需要注意:async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。