前提:
- 了解什么是同步任务,什么是异步任务,以及宏任务和微任务
- 了解了事件循环的基本原理
- 参考:JS 事件循环 同步任务 + 异步任务(宏任务 + 微任务)
async function fn1() {
console.log(2)
await fn2()
console.log(6)
}
async function fn2() {
new Promise(resolve => {
console.log(3)
resolve(5)
}).then(res => {
console.log(res)
}).then(() => {
console.log(7)
})
}
console.log(1)
fn1()
console.log(4)
不卖关子,输出答案是
1 2 3 4 5 6 7
解释:
- 首先输出1;
- 执行
fn1
,输出2; - 开始执行
fn2
,输出3,并resolve(5)
,fn2、fn1
中的第一层代码中不再出现同步代码,于是我们的视线跳出这2个函数,找到了console.log(4)
,输出4; - 回到
resolve(5)
,这里执行了resolve
,于是看到后面的第一个then
,是微任务,暂不执行,放入微任务队列(queue == [console.log(res)]
); - 然后看到第二个
then
,由于第一个then
中的代码没有执行(处于微任务队列中),所以第二个then
中的代码我们暂不关心(具体原因后面会说); fn2
中的代码执行结束(尽管还有事件未被执行或放入队列),因为整个fn2
中没有任何return
,于是await
得到了一个Promise.resolve(undefined)
,并且包裹了console.log(6)
,代码可以这样理解:
await fn2()
console.log(6)
// 等价于
Promise.resolve(undefined).then(() => {
console.log(6)
})
- 所以我们相当于看到了一个微任务,将其放入微任务队列
(queue == [then(() => console.log(res)).then(() => console.log(7)), then(() => console.log(6))]
); - 然后我们发现没有任何其他任务了,于是开始执行微任务队列中的事件,取出并执行
console.log(res)
,输出 5; - 执行到这里的时候,第一个
then
内自动执行了一个Promise.resolve(undefined)
,将undefined
传给了第二个 then,并将第二个then
放入微任务队列(queue == [then(() => console.log(6)), then((undefined) => console.log(7))]
),然后这里的两个任务按照队列顺序执行即可,输出6,7。
整个输出结束。
如果我们这样书写,会更好理解:
async function fn1() {
console.log(2)
await fn2()
console.log(6)
}
async function fn2() {
new Promise(resolve => {
console.log(3)
resolve(5)
}).then(res => {
console.log(res)
return Promise.resolve(undefined)
}).then(() => {
console.log(7)
})
}
console.log(1)
fn1()
console.log(4)
输出: 1 2 3 4 5 6 7
当我们这样写时,就会更明显:
async function fn1() {
console.log(2)
await fn2()
console.log(6)
}
async function fn2() {
new Promise(resolve => {
console.log(3)
resolve(5)
}).then(res => {
console.log(res)
return new Promise(resolve1 => {
resolve1(7)
})
}).then((res1) => {
console.log(res1) // 7
})
}
console.log(1)
fn1()
console.log(4)
输出:1 2 3 4 5 6 7
单独讨论一下第一个 then
:
...
}).then(res => {
console.log(res)
// 省略了一句 retuen Promise.resolve(undefined)
// 当我们不给后方的 then 传递 Promise 时,
// 会自动传递一个 Promise.resolve(undefined)
}).then((res1) => {
console.log(res1) // 7
})
...