承诺中的重新抛出错误

Tyl*_*den 68 javascript promise

我在教程中找到了以下代码:

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});
Run Code Online (Sandbox Code Playgroud)

我有点困惑:抓住电话会做什么吗?在我看来,它没有任何影响,因为它只是抛出了被捕获的相同错误.我的基础是常规try/catch的工作原理.

jfr*_*d00 90

当你表现出来时,没有任何关系可以进行裸体捕捉和投掷.除了添加代码和执行缓慢之外,它没有做任何有用的事情.所以,如果你要去.catch()重新抛出,那么你应该做一些你想做的事情.catch(),否则你应该完全删除它.catch().

通用结构的通常要点是,当您想要执行某些操作时,.catch()例如记录错误或清理某些状态(如关闭文件),但您希望promise链继续被拒绝.

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});
Run Code Online (Sandbox Code Playgroud)

在教程中,可能只是为了向人们展示他们可以捕获错误的位置,或者教导处理错误的概念,然后重新抛出它.


捕获和重新抛出的一些有用原因如下:

  1. 您想记录错误,但保留承诺链被拒绝.
  2. 您希望将错误转换为其他错误(通常是为了在链的末尾更容易进行错误处理).在这种情况下,您将重新抛出另一个错误.
  3. 您希望在承诺链继续之前进行一系列处理(例如关闭/免费资源),但您希望承诺链保持拒绝.
  4. 如果出现故障,您希望在promise链中的此点为调试器设置断点.

但是,在catch处理程序中没有其他代码的同一错误的普通捕获和重新抛出对正常运行代码没有任何帮助.

  • @Cherry - 你不能说这是一种不好的做法.有时候模块想以自己的方式记录自己的错误,这是一种方法.除此之外,我不建议这一点,我只是解释说,没有理由有`.catch()',并抛出了同样的错误捕捉里面,除非你做的`.catch别的东西()`.这就是这个答案的重点. (21认同)
  • 一般来说,异常应该符合抽象级别。例如,捕获与数据库相关的异常并抛出类似“服务”异常的异常(将由调用者处理)是完全可以的。当您不知道如何公开有关低级异常的详细信息时,这特别有用 (2认同)
  • 捕获和(有时)抛出的另一个好理由是处理特定的错误,但将其他所有错误都抛出。 (2认同)
  • @SimonZyx - 是的,“.finally()”对此非常有用,但有时资源已经在非错误路径中得到处理,因此“.catch()”仍然是关闭它们的地方。这确实取决于具体情况。 (2认同)

Phi*_*tan 12

两者.then().catch()方法都返回Promises,如果在任一处理程序中抛出异常,则返回的promise将被拒绝,并且异常将在下一个拒绝处理程序中捕获.

在下面的代码中,我们在第一个中抛出一个异常.catch(),它在第二个中被捕获.catch():

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});
Run Code Online (Sandbox Code Playgroud)

第二个.catch()返回一个已实现的Promised,.then()可以调用该处理程序:

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});
Run Code Online (Sandbox Code Playgroud)

有用的参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

希望这可以帮助!


tri*_*cot 6

如果完全省略方法调用,则没有重要区别catch

它唯一添加的是一个额外的微任务,这在实践中意味着您会注意到承诺的拒绝晚于没有条款的承诺失败的情况catch

下一个片段演示了这一点:

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );
Run Code Online (Sandbox Code Playgroud)

请注意如何在第一次拒绝之前报告第二次拒绝。这是唯一的区别。