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");
async1();
console.log("script end");
// 输出顺序:
// script start
// async1 start
// async2
// script end
// async1 end
我不太理最后2个的输出顺序为什么不是先async1 end,再script end请详细解释一下
解答
你遇到的这个问题涉及到 JavaScript 的事件循环机制和 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");
async1();
console.log("script end");
事件循环和任务队列
JavaScript 是单线程的,执行任务有两种类型:
- 同步任务:这些任务会立即执行,直接进入主线程。
- 异步任务:这些任务(如
setTimeout
、Promise
、async/await
)不会立即执行,它们会在主线程空闲后通过事件循环执行。async/await
是基于Promise
的,会将await
后面的代码加入到微任务队列中。
微任务(Microtask)优先级比宏任务(Macrotask)高。
执行顺序解析
-
console.log("script start")
:这是同步任务,立即执行,输出:script start
-
async1()
调用:async1
是异步函数,它会立即执行到await async2()
之前的同步代码。也就是console.log("async1 start")
,输出:async1 start
-
await async2()
:当遇到await
时,async1
的执行会暂停,直到async2()
返回的Promise
被解析(resolved
)。但async2()
是一个普通的异步函数,没有await
,它会立即执行console.log("async2")
,输出:async2
这里,
async2()
运行完后,没有返回Promise
,所以await
被视为等待一个已经解决的Promise
。但即使是这样,await
后面的代码(console.log("async1 end")
)会被放入微任务队列中,不会立即执行。 -
console.log("script end")
:这也是同步任务,会立即执行,输出:script end
-
微任务队列:同步任务执行完毕后,JavaScript 事件循环会检查微任务队列。在这里,
await
后面的代码console.log("async1 end")
会从微任务队列中取出执行,输出:async1 end
最终输出顺序
- script start(同步任务)
- async1 start(同步任务)
- async2(同步任务)
- script end(同步任务)
- async1 end(微任务)
总结:await
后面的代码不会立即执行,而是进入微任务队列,等待主线程上的同步任务完成后才执行。所以,script end
会先输出,async1 end
在微任务队列中排队,最后执行。