You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何throw Error会使async函数中被await的闭包同步执行?

问题解析:同步抛错与await的执行顺序差异

要搞懂这三个示例的输出差异,核心是理解await处理同步执行代码时的两种分支逻辑:同步抛错 vs 正常返回值。

1. 示例1:传入异步函数的情况

当传入async () => { throw new Error() }时,这个异步函数本身会返回一个rejected状态的Promise。await遇到Promise时,会暂停当前函数执行,把后续的catch/finally逻辑放到微任务队列,随后让出执行权给当前同步栈。

执行顺序:

  • 调用load,执行到await closure(),closure返回rejected Promise,load的后续逻辑进入微任务
  • 同步栈继续执行console.log("hello")
  • 同步栈清空后,执行微任务队列中的catch和finally,输出error和finished

最终输出顺序:hello → error → finished

2. 示例2:同步函数抛错的情况

当传入普通同步函数() => { throw new Error() }时,await closure()的执行逻辑发生了变化:

  • 先同步执行closure函数,此时直接抛出错误——这个错误发生在await进行Promise包装之前
  • 错误立即触发try块的catch分支,console.log("error")同步执行
  • 接着finally块也同步执行,输出finished
  • 等load函数的同步执行部分全部完成后,才回到全局同步栈,执行console.log("hello")

这里的关键是:同步函数的抛错不会被包装成Promise的reject,而是直接在当前同步执行流程中触发捕获逻辑,完全没有异步调度的参与。

3. 示例3:同步函数正常返回的情况

当传入() => { return 1 }时,await closure()的逻辑和示例1一致:

  • 同步执行closure函数,得到返回值1
  • await会把这个非Promise值包装成resolved状态的Promise
  • load的后续逻辑(仅finally)被放到微任务队列
  • 同步栈继续执行console.log("hello")
  • 同步栈清空后执行微任务,输出finished

最终输出顺序:hello → finished

总结

  • 如果await后面的表达式同步抛出错误,错误会在当前同步栈中直接被捕获,后续的catch/finally同步执行
  • 如果await后面的表达式返回Promise(异步函数或手动创建的),或者返回非Promise值(会被包装成resolved Promise),后续逻辑会进入微任务队列,等待同步栈清空后执行

内容的提问来源于stack exchange,提问作者Jose Carlos Ramírez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:42:47