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