javascript - How do I catch ES6 Promise rejections and completely stop flow? - Stack Overflow

Say I have 4 functions: runA(), runB(), runC() and runD().Using ES6 promises, in a pletely successful r

Say I have 4 functions: runA(), runB(), runC() and runD().

Using ES6 promises, in a pletely successful run, these would all be run one after another:

runA()
.then(runB)
.then(runC)
.then(runD)

If runA or runB fail (reject or throw), I would like to call error1() and then pletely stop the chain (not call runC or runD ). This makes me think I should add a single .catch() at the very end of the .then promise chain:

runA()
.then(runB)
.then(runC)     //won't get called if runA or runB throws
.then(runD)     //won't get called if runA or runB throws
.catch(error1)

But if runC fails, I would like to call error2() and still stop the chain (not call runD).

runA()
.then(runB)   
.catch(error1)  //moved up to only handle runA and runB
.then(runC)     //but now this gets called after error1() is run
.then(runD)     
.catch(error2)

Now that I have 2 catch calls in the chain, runC will get called after error1 is run since the result of the catch will default to a resolve. Is my only option to have the error1 function create a promise that it always rejects?

Say I have 4 functions: runA(), runB(), runC() and runD().

Using ES6 promises, in a pletely successful run, these would all be run one after another:

runA()
.then(runB)
.then(runC)
.then(runD)

If runA or runB fail (reject or throw), I would like to call error1() and then pletely stop the chain (not call runC or runD ). This makes me think I should add a single .catch() at the very end of the .then promise chain:

runA()
.then(runB)
.then(runC)     //won't get called if runA or runB throws
.then(runD)     //won't get called if runA or runB throws
.catch(error1)

But if runC fails, I would like to call error2() and still stop the chain (not call runD).

runA()
.then(runB)   
.catch(error1)  //moved up to only handle runA and runB
.then(runC)     //but now this gets called after error1() is run
.then(runD)     
.catch(error2)

Now that I have 2 catch calls in the chain, runC will get called after error1 is run since the result of the catch will default to a resolve. Is my only option to have the error1 function create a promise that it always rejects?

Share Improve this question edited Feb 12, 2016 at 15:14 jib 42.6k17 gold badges108 silver badges165 bronze badges asked Dec 24, 2015 at 6:45 rwstonebackrwstoneback 831 silver badge7 bronze badges 2
  • What's wrong with using only one .catch()? You can do error triage in the catch callback (if (error1) error1() else if (error2) error2()...). The Error object you throw can have a message and a name (could be the type like you need, 'RunCError' for example). – Shanoor Commented Dec 24, 2015 at 7:29
  • of course, you meant runA() .then(runB) .then(runC) .then(runD) - ... other than that, if you really can not determine what caused the error, you can throw at the end of error1 to skip past runC and runD - but you'll need to determine in error2 that the error came from A or B rather than C or D anyway – Jaromanda X Commented Dec 24, 2015 at 8:04
Add a ment  | 

3 Answers 3

Reset to default 4

No, having error1 create a promise that always rejects, is not your only option.

You can exploit the fact that .then takes two arguments:

.then(onSuccess, onFailure)

When given two arguments, there's an under-appreciated effect that onFailure will not catch failures in onSuccess. This is usually undesirable, except here, where you can use this fact to branch your decision tree:

runA()
.then(runB)
.then(() => runC().then(runD), error1)
.catch(error2)

This does what you want.

  • if runA or runB fail, then error1 is called and chain stops.
  • if runC or runD fail, then error2 is called and chain stops.

You can also write it like this:

runA()
.then(runB)
.then(() => runC()
  .then(runD)
  .catch(error2),
error1)

var log = msg => div.innerHTML += "<br>" + msg;

// Change which one of these four rejects, to see behavior:
var runA = () => Promise.resolve().then(() => log("a"));
var runB = () => Promise.reject().then(() => log("b"));
var runC = () => Promise.resolve().then(() => log("c"));
var runD = () => Promise.resolve().then(() => log("d"));
var error1 = () => log("error1");
var error2 = () => log("error2");

runA()
.then(runB)
.then(() => runC().then(runD), error1)
.catch(error2)
<div id="div"></div>

Try modifying which one fails in this fiddle.

What's wrong with using only one .catch()? You can do error triage in the catch callback (if (error1) error1() else if (error2) error2()...). The Error object you throw can have a message and a name (could be the type like you need, 'RunCError' for example).

runA()
    .then(runB)
    .then(runC)     // won't get called if runA or runB throws
    .then(runD)     // won't get called if runA or runB throws
    .catch(handleErrors)

function runA() {
    // ...

    if (err) {
        var error = new Error('Something is wrong...');
        error.name = 'RunAError';
        throw error;
    }
}

function runB() {
    // ...

    if (err) {
        var error = new Error('Something is wrong...');
        error.name = 'RunBError';
        throw error;
    }
}

function runC() {
    // ...

    if (err) {
        var error = new Error('Something is wrong...');
        error.name = 'RunCError';
        throw error;
    }
}

function runD() {
    // ...

    if (err) {
        var error = new Error('Something is wrong...');
        error.name = 'RunDError';
        throw error;
    }
}

function handleErrors(err) {
    if (err.name == 'RunAError') {
        handleAError();
    }

    if (err.name == 'RunBError') {
        handleBError();
    }

    // so on...
}

I just stumbled on the same problem and my solution is so far to explicitly invoke a reject in a catch like in this js bin: https://jsbin./yaqicikaza/edit?js,console

Code snippet

const promise1 = new Promise( ( resolve, reject ) => reject( 42 ) );

promise1
  .catch( ( err ) => console.log( err ) ) // 42 will be thrown here
  .then( ( res ) => console.log( 'will execute' ) ) // then branch will execute


const promise2 = new Promise( ( resolve, reject ) => reject( 42 ) );

promise2
  .catch( ( err ) => Promise.reject( ) ) // trigger rejection down the line
  .then( ( res ) => console.log( 'will not execute' ) ) // this will be skipped

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745325477a4622635.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信