记录一道神奇的题,有助于理解async、await
看下面这道题的结果是什么?
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')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
答案
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
执行过程如下:
首先执行同步任务,即
console.log('script start')
输出->>script start
setTimeout(function(){
console.log('setTimeout')
},0)
将任务放入宏任务队列
async1();
这里来分析一下async1
这个函数是如何执行的。
先了解以下await/async
MDN是这样描述await的:
async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果。
什么意思呢?这里引用一个答主的回答:
SegmentFault评论里 Linhh的回答
async可以看成一个promise即
// 原来 async 内部的代码
// await 上面的代码
doA()
await xxx
// await 下面的代码
doB()
// 相当于
new Promise(resolve => {
// 创建 promise 实例的时候,放的是 await 前面的代码
doA()
// await 后面的表达式相当于 resolve(xxx)
resolve(xxx)
}).then(data => {
// await 下面的代码
doB()
})
那么将其应用到本题中就是:
new Promise((resolve, reject) => {
console.log("async1 start");
console.log("async2");
resolve(Promise.resolve());
}).then(() => {
console.log("async1 end");
});
相当于
new Promise(
(resolve, reject) => {
console.log("async1 start");
console.log("async2");
}
).then(
()=>new Promise()
).then(
() => {
console.log("async1 end");
})
这会将
new Promise().then(
() => {
console.log("async1 end");
}
)
放入微任务队列
那么这块代码就输出
async1 start
async2
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
输出
promise1
将
function(){
console.log('promise2')
}
放入微任务队列
console.log('script end')
输出script end
同步任务完成,开始异步任务,先看微任务队列,
遇到:
new Promise().then(
() => {
console.log("async1 end");
}
)
这时候会将
() => {
console.log("async1 end");
}
放入微任务队列队尾,再从队头取出任务
function(){
console.log('promise2')
}
即输出promise2
继续检查微任务队列发现
() => {
console.log("async1 end");
}
即输出async1 end
继续检查微任务队列为空
调取宏任务队列队头任务即
function(){
console.log('setTimeout')
}
即输出setTimeout