为何async函数同步段的错误处理与普通函数存在差异?
为什么async函数同步代码的错误无法被外层try/catch捕获?
代码对比
第一段代码(普通立即执行函数)
try { console.log('start') const test = (() => { console.log('inside') const a = null; a.c = 1 })() console.log('end') } catch (error) { console.log('nvmnghia'); console.error(error); } // 输出: // start // inside // nvmnghia // TypeError: Cannot set properties of null (setting 'c')
第二段代码(async立即执行函数)
try { console.log('start') const test = (async () => { // 注意添加了async但无await console.log('inside') const a = null; a.c = 1 })() console.log('end') } catch (error) { console.log('nvmnghia'); console.error(error); } // 输出: // start // inside // end // Uncaught (in promise) TypeError: Cannot set properties of null (setting 'c') // 未输出nvmnghia,说明错误未被捕获
问题
第一段代码的错误被try/catch成功捕获,第二段代码的错误却未被捕获,反而触发了未处理的Promise错误。明明async函数中首个await之前的代码是同步执行的,为什么两者的错误处理表现完全不同?
解答
核心原因在于async函数的本质特性:不管函数内部是否包含await关键字,只要是async函数,执行后必然返回一个Promise对象。而且函数内部抛出的任何错误(包括同步代码的错误),都会被async函数自动捕获,并将返回的Promise标记为rejected状态,不会直接向外抛出到当前的同步执行栈中。
- 第一段代码里,普通立即执行函数抛出的是同步错误,会直接进入当前的同步执行上下文,因此外层的
try/catch可以直接捕获到这个错误。 - 第二段代码中,async立即执行函数内部的同步代码虽然是同步运行的,但抛出的错误被async函数拦截,转而包装成一个rejected的Promise返回给变量
test。此时外层的try/catch属于同步代码,只能捕获当前同步执行栈中抛出的错误,无法捕获Promise内部的reject错误。
如果要捕获async函数中的错误,需要用以下两种方式:
- 给返回的Promise调用
.catch()方法:
const test = (async () => { console.log('inside') const a = null; a.c = 1 })().catch(error => { console.log('nvmnghia'); console.error(error); });
- 用
await配合try/catch(外层需包裹async函数):
(async () => { try { console.log('start') const test = await (async () => { console.log('inside') const a = null; a.c = 1 })() console.log('end') } catch (error) { console.log('nvmnghia'); console.error(error); } })()
内容的提问来源于stack exchange,提问作者Minh Nghĩa
相关产品推荐
相关产品推荐

