async函数在try/catch中的执行上下文与错误捕获疑问
问题解析:async/await中try/catch的错误捕获机制
示例代码
async function foo() { try { const response = await fetch("https://www.xxx.xxx"); const data = await response.json(); console.log(data); } catch (e) { console.log("Error!!: ", e); } } foo(); console.log('111');
执行结果
先输出 111,再输出 Error!!: TypeError: Failed to fetch
核心困惑
当console.log('111')执行时,foo的执行上下文已经移出调用栈,为什么foo里的catch还能捕获到fetch的错误?
详细执行流程与错误捕获原理
- 调用
foo(),foo的执行上下文被创建并推入调用栈。 - 进入try块,执行
fetch("https://www.xxx.xxx"):fetch的执行上下文入栈,发起网络请求后返回一个pending状态的Promise,随后fetch的执行上下文出栈。 - 遇到
await关键字:JS引擎会暂停foo的执行,将foo的执行上下文从调用栈中弹出,但会完整保存上下文的所有状态(包括try/catch的作用域、变量、暂停位置等)。同时,为fetch返回的Promise注册两个回调:- 如果Promise变为resolved,就恢复foo的执行上下文,继续执行
const data = await response.json()及后续代码; - 如果Promise变为rejected,就恢复foo的执行上下文,直接进入catch块处理错误。
这组回调会被加入微任务队列等待执行。
- 如果Promise变为resolved,就恢复foo的执行上下文,继续执行
- foo暂停后,调用栈为空,全局代码继续执行
console.log('111'),控制台输出111。 - 全局代码执行完毕,调用栈再次为空,JS引擎开始处理微任务队列。此时fetch的网络请求失败,Promise状态变为rejected,对应的错误处理回调被取出并推入调用栈。
- foo的执行上下文被重新恢复并推入调用栈,因为Promise是rejected状态,所以直接进入try块对应的catch分支,执行错误输出逻辑,控制台打印错误信息。
简单来说:await只是暂停foo的执行,而非终结,foo的上下文会被保留。当Promise状态改变时,foo的上下文会被恢复,此时try/catch的作用域依然有效,rejected的错误会被直接导向catch块——整个过程中,try/catch始终覆盖着await操作的逻辑,不管中间是否有暂停和上下文的移出/恢复。
内容的提问来源于stack exchange,提问作者skwFE
相关产品推荐
相关产品推荐

