简体   繁体   English

Promise链在拒绝后继续

[英]Promise chain continues after rejection

I'm having trouble to properly catch an error/reject in a promise chain.我无法正确捕获 promise 链中的错误/拒绝。

 const p1 = () => { return new Promise((resolve, reject) => { console.log("P1"); resolve(); }); }; const p2 = () => { return new Promise((resolve, reject) => { console.log("P2"); reject(); }); }; const p3 = () => { return new Promise((resolve, reject) => { console.log("P3"); resolve(); }); }; p1().catch(() => { console.log("Caught p1"); }).then(p2).catch(() => { console.log("Caught p2"); }).then(p3).catch(() => { console.log("Caught p3"); }).then(() => { console.log("Final then"); });

When the promise is rejected, the following .then still gets executed.当 promise 被拒绝时,下面的.then仍然会被执行。 In my understanding, when in a promise chain an error/reject happened, the .then calls that follow it are not executed any more.据我了解,当在 promise 链中发生错误/拒绝时,其后的.then调用将不再执行。

P1
P2
Caught p2
P3
Final then

The rejection gets caught correctly, but why is "P3" logged after the catch?拒绝被正确捕获,但为什么在捕获后记录“P3”?

What am I doing wrong?我究竟做错了什么?

To clarify @evolutionxbox, this is my expected result:为了澄清@evolutionxbox,这是我的预期结果:

 Promise.resolve().then(() => { console.log("resolve #1"); return Promise.reject(); }).then(() => { console.log("resolve #2"); return Promise.resolve(); }).then(() => { console.log("resolve #3"); return Promise.resolve(); }).then(() => { console.log("Final end"); }).catch(() => { console.log("Caught"); });

This code works exactly like it should.这段代码的工作方式与它应该的完全一样。 And I can't see a difference to my code, except that I declared the functions separately.而且我看不出我的代码有什么不同,除了我分别声明了这些函数。

The code above stops no matter where the promise is rejected.无论 promise 在哪里被拒绝,上面的代码都会停止。

Try this.尝试这个。

 const p1 = (arg) => { // Promise returns data in the respected arguments return new Promise((resolve, reject) => { // Data to be accessed through first argument. resolve(arg); }); }; const p2 = (arg) => { return new Promise((resolve, reject) => { // Data to be accessed through second argument. reject(arg); }); } p1('p1').then(resolve => { console.log(resolve + ' is handled with the resolve argument. So it is accessed with.then()'); }) // Since reject isn't configured to pass any data we don't use.catch() p2('p2').catch(reject => { console.log(reject + ' is handled with the reject argument. So it is accessed with.catch()'); }) // Since resolve ins't configured to pass any data we don't use.then() // You would normally configure a Promise to return a value on with resolve, and access it with.then() when it completes a task successfully. //.catch() would then be chained on to the end of.then() to handle errors when a task cannot be completed. // Here is an example. const p3 = () => { return new Promise((resolve, reject) => { var condition = true; if (condition === true) { resolve('P3'); } else { reject('Promise failed;'); } }); }. p3('p3').then(resolve => { console;log(resolve). }).catch(reject => { console;log(reject); })

Here is a synchronous equivalent of your code:这是您的代码的同步等效项:

 const f1 = () => { console.log("F1"); }; const f2 = () => { console.log("F2"); throw new Error(); }; const f3 = () => { console.log("F3"); }; try { f1(); } catch { console.log("Caught f1"); } try { f2(); } catch { console.log("Caught f2"); } try { f3(); } catch { console.log("Caught f3"); } console.log("Final code");

As you can see, that gives a matching result.如您所见,这给出了匹配的结果。 Hopefully, looking at the synchronous code you would not be surprised why.希望看到同步代码你不会对为什么感到惊讶。 In a try..catch you are allowed to attempt recovery.try..catch中,您可以尝试恢复。 The idea is that the catch will stop the error propagation and you can hopefully continue further.这个想法是catch停止错误传播,您可以希望进一步继续。 Or if you do want to stop, you still have to explicitly throw again, for example:或者,如果您确实想停止,您仍然必须再次明确地throw ,例如:

doCode();

try {
    makeCoffee();
} catch(err) {
    if (err instanceof IAmATeapotError) {
        //attempt recovery
        makeTea();
    } else {
        //unrecoverable - log and re-throw
        console.error("Fatal coffee related issue encountered", err);
        throw err;
    }
}

doCode();

This is also the purpose Promise#catch() serves - so you can attempt recovery or at least act when there was a problem.这也是Promise#catch()服务的目的 - 因此您可以尝试恢复或至少在出现问题时采取行动。 The idea is that after the .catch() you might be able to continue:这个想法是,.catch()之后,您可能可以继续:

 const orderPizza = (topping) => new Promise((resolve, reject) => { if (topping === "pepperoni") reject(new Error("No pepperoni available")); else resolve(`${topping} pizza`); }); const makeToast = () => "toast"; const eat = food => console.log(`eating some ${food}`); async function main() { await orderPizza("cheese").catch(makeToast).then(eat); console.log("-----"); await orderPizza("pepperoni").catch(makeToast).then(eat); } main();

In order to reject the promise chain from a .catch() you need to do something similar as a normal catch and fail at the error recovery by inducing another error.为了从.catch()中拒绝 promise 链,您需要执行与正常catch类似的操作,并通过引发另一个错误来导致错误恢复失败 You can throw or return a rejected promise to that effect .您可以throw或返回被拒绝的 promise 以达到该效果

This code works exactly like it should.这段代码的工作方式与它应该的完全一样。 And I can't see a difference to my code, except that I declared the functions separately.而且我看不出我的代码有什么不同,除了我分别声明了这些函数。

The code above stops no matter where the promise is rejected.无论 promise 在哪里被拒绝,上面的代码都会停止。

The second piece of code you show fails entirely after a reject because there are no other .catch() -es that are successful.您显示的第二段代码在拒绝后完全失败,因为没有其他成功的.catch() -es。 It is basically similar to this synchronous code:它基本上类似于这个同步代码:

 try { console.log("log #1"); throw new Error(); console.log("log #2"); console.log("log #3"); console.log("Final end"); } catch { console.log("Caught"); }

Thus if you do not want to recover early, you can also skip the .catch() instead of inducing another error.因此,如果您不想提前恢复,您也可以跳过.catch()而不是引发另一个错误。

You do not do anything wrong.你没有做错任何事。 In your code you call the first promise p1 .在您的代码中,您调用第一个 promise p1 Then you write p1.catch(...).then(...).then(...).then(...) .然后你写p1.catch(...).then(...).then(...).then(...) This is a chain which means that you should call then 3 times, because you called resolve method in the p1 promise (all these then s depend on the first promise).这是一个链,意味着您应该调用then 3 次,因为您在p1 promise 中调用了 resolve 方法(所有这些then都取决于第一个承诺)。

When the promise is rejected, the following .then still gets executed.当 promise 被拒绝时,下面的.then仍然会被执行。

Yes.是的。 Just to be accurate: the then and catch method calls are all executed synchronously (in one go), and so all promises involved are created in one go.准确地说: thencatch方法调用都是同步执行的(一口气),因此所有涉及的 Promise 都在一个 go 中创建。 It's the callbacks passed to these methods that execute asynchronously, as the relevant promises resolve (fullfill or reject).传递给这些方法的回调是异步执行的,因为相关的 Promise 解决(完成或拒绝)。

In my understanding, when in a promise chain an error/reject happened, the .then calls that follow it are not executed any more.据我了解,当在 promise 链中发生错误/拒绝时,其后的.then调用将不再执行。

This is not the case.不是这种情况。 The promise that a catch returns can either fullfill or reject depending on what happens in the callback passed to it, and so the callbacks further down the chain will execute accordingly when that promise resolves.根据传递给它的回调中发生的情况, catch返回的 promise 可以完全填充或拒绝,因此当 promise 解析时,链中下游的回调将相应地执行。

The rejection gets caught correctly, but why is "P3" logged after the catch?拒绝被正确捕获,但为什么在捕获后记录“P3”?

As in your case the catch callback returns undefined (it only performs a console.log ), its promise fullfulls , By consequence, the chained then callback -- on that promise -- is executed... etc.在您的情况下, catch回调返回undefined (它只执行console.log ),它的 promise fullfulls ,因此,链式then回调 - 在promise上 - 被执行......等等。

If you want to "stop"如果你想“停止”

If you want to keep the chain as it is, but wish to have a behaviour where a rejection leads to no further execution of then or catch callbacks, then don't resolve the associated promise:如果你想保持链原样,但希望有一个拒绝导致不再执行thencatch回调的行为,那么不要解析相关的 promise:

 const stop = new Promise(resolve => null); const p1 = () => { return new Promise((resolve, reject) => { console.log("P1"); resolve(); }); }; const p2 = () => { return new Promise((resolve, reject) => { console.log("P2"); reject(); }); }; const p3 = () => { return new Promise((resolve, reject) => { console.log("P3"); resolve(); }); }; p1().catch(() => { console.log("Caught p1"); return stop; // don't resolve }).then(p2).catch(() => { console.log("Caught p2"); return stop; }).then(p3).catch(() => { console.log("Caught p3"); return stop; }).then(() => { console.log("Final then"); });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM