How do I catch ES6 Promise rejections and completely stop flow?

↘锁芯ラ 提交于 2019-11-30 23:34:44

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.com/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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!