为什么Try Catch块没有捕获Promise异常?

2022-04-03 00:00:00 exception javascript es6-promise

我对承诺的错误处理感到困惑。答案可能很明显,但我不明白。

我有以下示例代码:

var test = async function(){
  throw new Error('Just another error')
}

try {
  test().then()
}
catch(err){
  alert('error: ' + err.toString())
}

在我的浏览器中,我没有收到警告,并且Uncaught (in promise) Error在控制台中。为什么会这样呢?是否应该使用Try..Catch块处理该错误?


解决方案

我可以看到您问题的两个可能方面:

  1. test中抛出的错误位于test的同步(非异步)部分。为什么它是承诺拒绝而不是同步例外?

  2. 来自test()的承诺正在被拒绝,为什么catch没有捕获该拒绝?

#1-为什么是拒绝?

因为即使async函数在其工作的同步部分抛出,这只是拒绝它返回的承诺,不会引发同步错误。这只是在设计async函数时做出的一个设计决定,而且是一个聪明的决定--如果在抛出函数的同步部分时是同步错误,但在那之后是承诺被拒绝,那将是混乱和难以理解的。所以很简单:抛出一个async函数总是拒绝它的承诺。

(这与Promise构造函数处理传入的Executor回调的方式一致。当您这样做时new Promise((resolve, reject) => /*...*/}),Promise构造函数同步调用您的函数,但如果您在调用过程中引发,它将使用您抛出的内容来拒绝Promise,而不是允许它作为同步异常继续。)

#2-catch块为什么没有捕获拒绝?

因为您没有使用await。只有当您正在履行承诺时,拒绝承诺才是例外。如果使用Promise方法then/catch/finally附加处理程序,则通过调用拒绝处理程序而不是异常机制来处理拒绝。

因此要么使用Promise方法附加履行处理程序,要么使用拒绝处理程序:

test()
.then(result => {
    // ...use `result` here...
})
.catch(error => {
    // ...handle/report error here...
});

或在async函数中使用await(如果您的环境中有顶级await,则在模块的顶层使用):

// In an `async` function (or the top level of a module in cutting-edge environments)
try {
    const result = await test();
    // ...use `result` here...
}
catch(err){
    // ...handle/report error here...
}

相关文章