Promise 与异步执行问题
参考知识点:
# 1. 字节:解释以下异步代码的输出顺序
#
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('settimeout')
})
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
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
输出结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 第 9 行,输出
'script start' - 第 10 行,向消息队列添加立即执行的
setTimeout任务,该任务为宏任务,在Promise微任务执行完毕后再执行 - 第 13 行,调用异步函数
async1,async1开始执行,输出第 2 行的'async1 start' - 第 3 行,
await后面为函数调用,为取得函数返回值,调用async2 - 第 7 行,
async2函数输出'async2',并返回undefined - 第 3 行,
await得到undefined,为立即可用的值,在消息队列中将undefined值及恢复async1执行添加为任务,async1暂停执行并退出 - 第 14 行,新
Promise开始执行,输出第 15 行的'promise1' - 第 16 行结束,
Promise落定,在消息队列中添加Promise落定执行then的任务 - 第 20 行,输出
'script end',至此,宏任务全部执行完毕 - JS 从消息队列中取出
undefined值和恢复async1执行的任务,恢复async1执行,程序回到第 3 行 - 第 4 行,输出
'async1 end',async1返回 - JS 从消息队列中取出
Promise落定执行then的任务,程序回到第 17 行 - 第 18 行,输出
'promise2',函数返回 - 微任务执行完毕,JS 从消息队列中取出立即执行的
setTimeout任务,程序回到第 11 行,并立即输出'settimeout'
# 2. 解释以下异步代码的输出顺序
console.log(1);
new Promise((resolve, reject) => {
console.log(2);
resolve("a");
console.log(3);
}).then(res => {
console.log(4);
setTimeout(() => {
console.log(res);
new Promise((resolve, reject) => {
console.log(5);
resolve("b");
console.log(6);
}).then(res => {
console.log(res);
});
console.log(7);
});
console.log(8);
});
console.log(9);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输出顺序:1 2 3 9 4 8 a 5 6 7 b
- 程序运行,输出
1,进入new Promise,输出2,Promise解决值为"a",输出3 .then()后面均为微任务,进入微任务队列,程序跳到最后一行,输出9- 宏任务清空,执行微任务,输出
4 setTimeout为宏任务,进入宏任务队列,程序跳到setTimeout后一行,输出8- 微任务清空,执行新的宏任务,输出
res即"a",并进入new Promise,输出5,Promise解决值为"b",输出6 .then()后面为微任务,进入微任务队列,程序跳到setTimeout最后一行,输出7- 第二次宏任务清空,执行微任务,输出
"b"
# 3. 解释以下异步代码的输出顺序
const myPromise = Promise.resolve(Promise.resolve("Promise!"));
function funcOne() {
myPromise.then(res => res).then(res => console.log(res));
setTimeout(() => console.log("Timeout!"), 0);
console.log("Last line!");
}
async function funcTwo() {
const res = await myPromise;
console.log(await res);
setTimeout(() => console.log("Timeout!"), 0);
console.log("Last line!");
}
funcOne();
funcTwo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输出顺序:Last line! Promise! Promise! Last line! Timeout! Timeout!
funcOne()运行,将myPromise的解决值(即"Promise!",原因见下)加入微任务队列- 将
setTimeout回调加入新的宏任务队列,延时为立即执行 - 输出
"Last line!",funcOne()结束运行 - 主线程宏任务没有结束,
funcTwo()运行 - 遇到
await,将myPromise的解决值(即"Promise!")加入微任务队列,函数退出运行 - 此时主线程已经没有宏任务,开始执行微任务
- 微任务 1:
funcOne()取得myPromise的解决值,即"Promise!",形成一个解决值为"Promise!"的Promise,继续调用then,加入微任务队列 - 微任务 2:
funcTwo()取得myPromise的解决值,即"Promise!",函数恢复运行,赋值给res;运行到await res,将res的值加入微任务队列,函数退出运行 - 微任务 3:
funcOne()取得新Promise的解决值,即"Promise!",将其打印,输出"Promise!" - 微任务 4:
funcTwo()取得res的值,即"Promise!",函数恢复运行,将其打印,输出"Promise!" funcTwo()继续运行,将setTimeout回调加入新的宏任务队列,延时为立即执行- 输出
"Last line!",funcTwo()结束运行 - 微任务队列已经清空,开始执行新的宏任务队列
- 执行
funcOne()中setTimeout的回调,输出"Timeout!" - 执行
funcTwo()中setTimeout的回调,输出"Timeout!"
注意
当 Promise.resolve() 的参数仍是一个 Promise 时,等同于空包装,即 Promise.resolve(Promise.resolve("Promise!")) 全等于 Promise.resolve("Promise!"),并且新包装的 Promise 保持内层 Promise 的状态。
在 GitHub 中编辑此页 (opens new window)
上次更新于: 2022/11/3 23:25:22