在承诺捕获中重新抛出错误


88

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

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

我有点困惑:catch调用可以完成任何事情吗?在我看来,它没有任何作用,因为它只会引发与捕获的错误相同的错误。我基于常规try / catch的工作原理。


您能否提供本教程的链接?也许还有其他背景会有所帮助...
Igor

@Igor我不能,它在Pluralsight上。这可能只是一些错误处理逻辑的占位符吗?
泰勒·德顿

这就是我的猜测,因为它不执行任何操作,然后将错误传递给调用方,这也可以通过不首先进行捕获来实现。
伊戈尔(Igor)

1
@TylerDurden我怀疑您是正确的占位符。
加里德·史密斯

@TylerDurden,我也猜想它是一个占位符。也许试图演示如何格式化/标准化错误。基本上与等价于try { ... }catch(error){ throw new Error("something went wrong") }。或表明承诺和错误是兼容的(至少是那样)。但是在当前的实现中,它只是愚蠢的。没错,它什么也没做,甚至不像您在OOP中添加的钩子一样,以便在继承类中覆盖它。我会在做某件事时立即添加catch块,但不是那样,不仅仅是作为占位符。
托马斯

Answers:


124

正如您所展示的,毫无意义地进行裸掷和扔掷。除了添加代码和执行缓慢之外,它没有任何用处。因此,如果您要返回.catch()并重新抛出,则应该在中执行某些操作.catch(),否则应将其.catch()完全删除。

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

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

在教程中,可能只是为了向人们展示他们可以在哪里发现错误,或者教给他们处理错误的概念,然后将其重新抛出。


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

  1. 您想记录错误,但将承诺链保持为拒绝状态。
  2. 您希望将错误转换为其他错误(通常是为了在链的末尾更轻松地进行错误处理)。在这种情况下,您将抛出另一个错误。
  3. 您希望在诺言链继续之前进行大量处理(例如关闭/释放资源),但希望诺言链保持被拒绝状态。
  4. 如果出现故障,您希望在承诺链的这一点上为调试器放置一个断点

但是,在catch处理程序中没有其他代码的情况下,简单地捕获并抛出相同的错误对于正常运行代码没有任何帮助。


我认为这不是一个很好的例子。通过这种方法,您很容易获得1个错误的多个日志记录。在Java中,您throw new Exception(periousException);不知道javascript是否支持嵌套错误,但是无论如何,“ log and throw”是不好的做法。
樱桃

26
@Cherry-您不能说这是一个坏习惯。有时候,模块想以自己的方式记录自己的错误,而这是做到这一点的一种方式。此外,我不建议您这样做,我只是在解释说,.catch()除非您在中进行了其他操作,否则没有理由在捕获中抛出a并引发相同的错误.catch()。这就是答案的重点。
jfriend00

通常,异常应该适合抽象级别。完全可以捕获例如与db相关的异常,并抛出类似“服务”的异常,该异常将由调用方处理。当您不公开有关低级别异常的详细信息时,此功能特别有用
maxTrialfire

3
捕获和(有时)抛出的另一个很好的理由是处理特定的错误,但是将其他所有东西都抛出。
贾斯珀(Jasper)

2
@SimonZyx-是的,这.finally()可能非常有用,但是有时资源已经在非错误路径中得到处理,因此.catch()仍然是关闭它们的地方。这确实取决于情况。
jfriend00

15

无论.then().catch()方法返回承诺,如果在任一处理程序抛出异常,返回的承诺被拒绝,异常会被夹在接下来的拒绝处理。

在下面的代码中,我们在第一个中抛出异常 .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);
});

第二个.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');
});

有用的参考资料:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

希望这可以帮助!


4

如果您没有 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) );

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


3

听起来您的问题是,“在诺言链中,该.catch()方法有什么作用?”

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/throw

throw语句“将停止(不会执行throw之后的语句),并将控制权传递给调用堆栈中的第一个catch块。如果调用方函数之间不存在catch块,则程序将终止。”

在Promise链中,该.then()方法将返回某种类型的数据块。块的返回将完成承诺。数据的成功返回完成了承诺。您可以.catch()以相同的方式来考虑该方法。 .catch()但是将处理不成功的数据检索。throw语句完成了诺言。有时,您会看到开发人员使用.catch((err) => {console.log(err))} 它来完成诺言链。


0

实际上,您实际上不需要重新抛出它,只需将Promise.catch保留为空,否则它将被视为取消处理拒绝,然后将代码包装在try catch中,它将自动捕获传递给错误的错误。

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}

0

在Promise链中,最好使用.catch

ex在函数f2中:.then(...)。catch(e => reject(e));

  • test1-尝试捕获
  • test2-无需尝试或.catch
  • test3-带.catch

function f1() {
    return new Promise((resolve, reject) => {
        throw new Error('test');
    });
}

function f2() {
    return new Promise((resolve, reject) => {
        f1().then(value => {
            console.log('f1 ok ???');
        }).catch(e => reject(e));
    });
}

function test1() {
    console.log('test1 - with try catch - look in F12');
    try {
      f2().then(() => { // Uncaught (in promise) Error: test
        console.log('???'); });
    } catch (e) {
      console.log('this error dont catched');
    }
}

function test2() {
    console.log('test2 - without try or .catch - look in F12');
    f2(); // Uncaught (in promise) Error: test
}

function test3() {
  console.log('test3 - with .catch');
  f2().then(value => {
    console.log('??');
  }).catch(e => {
    console.log(' now its ok, error ', e);
  })
}

setTimeout(() => { test1(); 
  setTimeout(() => { test2(); 
    setTimeout(() => { test3(); 
    }, 100);
  }, 100);
}, 100);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.