承诺捕捉中的重抛错误

我在一个教程中发现了以下代码:

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

我有点困惑: 这个接球调用有什么作用吗?在我看来,它似乎没有任何效果,因为它只是抛出了被捕获的相同错误。这是基于常规 try/catch 的工作原理。

79295 次浏览

因此,听起来你的问题是: “在承诺链中,.catch()方法做什么?”

Https://developer.mozilla.org/en-us/docs/web/javascript/reference/statements/throw

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

在承诺链中,.then()方法将返回某种类型的数据块。这个块的返回将完成这个承诺。数据的成功返回实现了这一承诺。您可以以同样的方式看待 .catch()方法。然而,.catch()将处理不成功的数据检索。抛出语句完成了承诺。有时,您会看到开发人员使用 .catch((err) => {console.log(err))},这也将完成承诺链。

如果完全忽略 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) );

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

没有必要像你展示的那样裸体接球和抛球。除了添加代码和缓慢的执行之外,它不做任何有用的事情。所以,如果你要重新抛出 .catch(),应该有一些你想做的事情在 .catch(),否则你应该只是删除 .catch()完全。

对于这种一般结构,通常的情况是当您想要在 .catch()中执行某些操作,比如记录错误或者清除某些状态(比如关闭文件) ,但是您希望承诺链继续被拒绝。

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

在教程中,它可能只是为了向人们展示他们在哪里可以捕获错误,或者教授处理错误的概念,然后再抛出它。


捕获和再抛弃的一些有用理由如下:

  1. 你想 log the error,但保持承诺链作为拒绝。
  2. 您希望使用 把错误变成其他错误(通常是为了在链的末尾更容易地处理错误)。在这种情况下,您将重新抛出一个不同的错误。
  3. 您希望 在承诺链继续之前做一系列的处理(比如关闭/释放资源) ,但是希望承诺链保持被拒绝状态。
  4. You want 放置调试器断点的点 at this point in the promise chain if there's a failure.
  5. 您想要 处理特定的错误或一组错误,但是重新抛出其他的,以便它们传播回调用者。

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

.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()返回一个已实现的“承诺”,.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/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

希望这个能帮上忙!

You actually don't need to re throw it, just leave the Promise.catch empty otherwise it will consider as un handle the reject and then wrap the code in a try catch and it will catch the error automatically which is passing down.

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
}

在承诺链中,最好使用

函数 f2中的 ex: 。然后(...)。捕捉(e = > 拒绝(e)) ;

  • Test1-使用 try catch
  • Test2-没有尝试或
  • Test3-with. 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);