近期复习async/await语法,发现await的暂停异步函数执行机制很有趣
发生这种情况时十分微妙,最慢的竟然比最快的还要快?
async function test() {
let a = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('最慢的','inner');
resolve('最慢的');
}, 3000);
});
let b = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('中等的','inner');
resolve('中等的');
}, 2000);
});
console.log(await a);
await Promise.resolve(setTimeout(() => console.log('最快的'), 1000));
console.log(await b);
console.log('end');
}
//输出结果:
//中等的 inner
//最慢的 inner
//最慢的
//中等的
//end
//最快的
关键在于await暂停的是异步函数代码的执行,看一下await的用法:
[返回值] = await [表达式]
返回值:
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身(被当做已解决的期约)。
表达式:
一个 Promise 对象或者任何要等待的值。
另外参考红书的一句话
回到代码中:
//执行中的异步期约,3秒后输出“最慢的”
console.log(await a);
//一个未执行的异步期约,1秒后输出“最快的”
await Promise.resolve(setTimeout(() => console.log('1'), 1000));
//执行中的异步期约,2秒后输出“中等的”
console.log(await b);
//同步代码
console.log('end');
理清一下代码的执行顺序:
- 等待a求值
- 等待Promise.resolve(setTimeout(() => console.log('1'), 1000))的求值
- 等待b的求值
进入代码后,期约a与b在第一时间就声明并且异步求值
a在3秒后解决,返回“最慢的”,解决前打印“最慢的 inner”
b在2秒后解决,返回“中等的”,解决前打印“中等的 inner”
此时碰到第一个await
js会等待a的求值,但别忘了上面引用红书说过await会暂停代码的执行,但函数的其余部分仍然会进行异步求值,b的求值也在异步进行中。
所以b理所应当的最先解决,并且打印了“中等的 inner”
随后,a解决,打印了“中等的 inner”
此时,a返回了“最慢的”,得以打印“最慢的”
到了第二个await了
await会怎么处理Promise.resolve(...)?
Promise.resolve(...)是一个已解决期约的初始化(同步代码),此时因为前面await在等待一个期约的解决,这个初始化被暂停了。
js运行至此,初始化了已解决期约,求得的值是定时器
setTimeout(() => console.log('1'), 1000)的id(因为他是第三个定时器所以是3)
Promise.resolve(...)成功被初始化,作为已解决期约,await能够直接求得它的值,完全不用等待
但是它的值是个定时器,并且期约被初始化后定时器才开始运行,1秒后输出“最快的”。
到了第三个await
如上文所说,期约b早已解决,await 直接求得了他的值“中等的”并直接打印
至此,await全部执行完成。
剩下的代码的还有
同步代码:console.log('end')
异步任务中的:定时器打印“最快的”
所以最终输出的顺序是
中等的 inner
最慢的 inner
最慢的
中等的
end
最快的