给定异步代码场景,代码块的执行顺序及原因是什么?
const mainFun = async () => { const promise1 = asyncFun() const promise2 = asyncFun() const promise3 = asyncFun() await Promise.all([promise1, promise2, promise3]) } const asyncFun = async () => { // 非异步计算,耗时1秒 someCalculation() // 快速异步调用,耗时1毫秒 await anotherAsyncFun() // 其他计算 otherCalculation() }
问题描述
忽略运行时长的现实差异,我原本预期执行流程为:
- 启动promise1,约1秒后遇到第一个await,等待期间寻找其他可执行代码
- 启动promise2,约1秒后遇到第一个await,等待期间寻找其他可执行代码
- 由于promise1的第一个await完成,继续执行otherCalculation
- [...]
但实际测试发现直觉错误——代码会先启动promise3,而非回到promise1继续执行。我不确定该用何种术语描述这种类似“深度优先”或“广度优先”的逻辑,想请教这段代码的执行顺序是什么?以及背后的原因?
执行顺序与核心原因解析
实际执行流程
- 进入
mainFun,首先执行const promise1 = asyncFun():- 立即进入
asyncFun,同步执行someCalculation(); - 遇到
await anotherAsyncFun()时,暂停asyncFun执行,将后续的otherCalculation()包装成微任务,同时返回一个未完成的Promise给promise1; - 主线程回到
mainFun,继续执行下一行同步代码。
- 立即进入
- 主线程执行
const promise2 = asyncFun():- 重复步骤1的过程,同步执行
someCalculation(),遇到await后暂停,返回Promise给promise2,主线程回到mainFun。
- 重复步骤1的过程,同步执行
- 主线程执行
const promise3 = asyncFun():- 同样同步执行
someCalculation(),遇到await后暂停,返回Promise给promise3,主线程回到mainFun。
- 同样同步执行
- 主线程执行
await Promise.all([promise1, promise2, promise3]),此时主线程挂起,等待所有传入的Promise完成。 - 当
anotherAsyncFun()的Promise resolve后,对应的微任务会被加入微任务队列;若三个Promise几乎同时完成,微任务会按promise1→promise2→promise3的顺序依次执行,即依次调用otherCalculation()。
关键原因说明
- 同步代码优先执行:JavaScript是单线程模型,调用栈中的同步代码会被全部执行完毕,才会处理事件队列中的微任务/宏任务。
mainFun中三个asyncFun()的调用属于同步操作,因此程序会先把每个asyncFun()的同步部分(someCalculation())依次执行完,不会在中途被异步任务打断。 - async/await的本质是Promise语法糖:
await会暂停当前async函数的执行,将函数剩余逻辑注册为Promise的回调(微任务),但这个回调不会立即执行——必须等当前调用栈清空后,才会开始处理微任务队列。 - Promise.all不影响前置同步逻辑:
Promise.all仅负责等待所有传入的Promise完成,不会改变前面三个asyncFun()的同步执行顺序,也不会提前触发微任务。
关于“深度/广度优先”的误区
这里并不适用深度或广度优先的描述,核心逻辑是同步执行优先级高于异步任务,以及调用栈的先进后出执行规则——主线程会先完成当前同步上下文的所有代码,再去处理异步任务队列。
内容的提问来源于stack exchange,提问作者oli
相关产品推荐
相关产品推荐

