首先看这么一段代码:
async function async1() {
console.log('a');
await async2();
console.log('b');
}
async function async2(){
console.log('c');
}
async1();
new Promise(function (resolve) {
console.log('d');
resolve();
}).then(function () {
console.log('e')
});
这一段代码的输出结果是什么呢?答案是
a
c
d
e
b
可能和某些人心里想的不太一样哈,那么接下来就让我们深入探究输出为以上顺序的原因:
先介绍一下ES2017(ES8)的新特性: async/await
,使用async function
声明的函数返回的是一个Promise
对象,当async函数返回值时,Promise
的rosolve方法会负责传递这个值;当async函数抛出异常时,Promise
的 reject 方法也会传递这个异常值。
async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果。
注意,await
关键字仅仅在async function
中有效。如果在async function
函数体外使用 await
,你只会得到一个语法错误(SyntaxError
)。
现在,让我们来分析这段代码, 我们声明了async1
和async2
这两个async函数,然后执行async1()
,首先执行console.log('a')
,然后执行async2()
中的console.log('c')
,执行完成后async2
返回的Promise状态变为fulfilled。然后,因为await
的存在,async1
暂停执行。
这里要注意,await语句之后的其它语句相当于await后表达式返回的Promise对象的then回调函数,所以async1
未执行的部分会进入microtask queue。
紧接着执行new Promise()
,作为其参数的函数会立刻执行,所以console.log('d')
被执行,执行resolve()
后这个Promise
的状态变成fulfilled,于是其then
方法的回调函数进入microtask queue。
照这样说,console.log('b')
在队列中更靠前,应该先输出才对,为什么最后输出呢?
其实,即使await关键字后是一个已经决议的Promise对象,此时也会产生一个新的Promise对象,虽然它会立刻resolve为原Promise的值,但该过程是异步过程,所以进入队列的其实是新Promise的产生,然后async1
剩下的语句添加到了队列的末尾,所以最后输出。