1. 问题
首先我们来看一段代码,你觉得这段代码的执行顺序是什么呢?
function resolveAfter2Seconds() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
console.log('A');
}
asyncCall();
console.log('B');
这段代码的输出顺序是:
1. "calling" (调用asyncCall函数时打印出来)
2. "B" (在asyncCall函数调用期间打印出来)
3. "resolved" (resolveAfter2Seconds函数中的Promise在2秒后被解决,await关键字等待解决并返回结果)
4. "A" (在await表达式之后打印出来)
2. 原因
那么为什么A是在最后才打印出来呢?这就是因为await会阻碍函数的执行,并一直等待Promise执行结束。
当调用asyncCall函数时,它会立即打印出"calling"。然后,它会在resolveAfter2Seconds函数中等待2秒钟,直到Promise解决为止。在等待期间,控制权返回给调用者,所以在等待期间打印的是"B"。当Promise解决后,结果被赋给result变量并打印出"resolved"。最后,控制权回到asyncCall函数,它继续执行并打印出"A"。
A是在"resolved"之后打印的,原因是在async函数中的await关键字。await关键字会暂停函数的执行,直到Promise解决为止,并返回解决的结果。在这种情况下,await关键字会等待resolveAfter2Seconds函数中的Promise解决,然后将解决的结果赋给result变量。 在这段代码中,当调用asyncCall函数时,它会立即打印出"calling"。然后,它会遇到await关键字,这会导致函数暂停执行并等待Promise解决。在等待期间,控制权返回给调用者(即全局作用域),所以在等待期间打印的是"B"。当Promise在2秒后解决时,await关键字会将解决的结果(即'resolved')赋给result变量。然后,控制权回到asyncCall函数,它继续执行并打印出"A"。 因此,"resolved"是在"A"之前打印的,因为await关键字会等待Promise解决,然后才会继续执行后面的代码。
3. 思考
通过上面的案例我们知道,当使用了await,Promise函数会进入等待期,会造成堵塞,但是会把控制权交给调用者,那我们做个拓展
3.1 把Promise中的定时器设置为0s
function resolveAfter2Seconds() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('resolved');
}, 0);
});
}
.......
//其余代码和上方相同
我们发现该种情况下的结果仍然和之前一样,这也代表了即使定时器是0s,Promise仍然会把控制权交给全局,等全局结束同步任务之后,Promise才执行