我如何捕获ES6 Promise拒绝并完全停止流动?

时间:2015-12-24 06:45:07

标签: javascript es6-promise

假设我有4个功能:runA()runB()runC()runD()

使用ES6承诺,在完全成功的运行中,这些都将一个接一个地运行:

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

如果runArunB失败(拒绝或抛出),我想致电error1(),然后完全停止连锁(不是致电runC或{{1 })。这让我觉得我应该在runD承诺链的最后添加一个.catch()

.then

但如果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) 失败,我想致电runC并仍然停止连锁(不是致电error2())。

runD

现在我在链中有2 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) 个调用,catch将在runC运行后被调用,因为catch的结果将默认为error1。我唯一的选择是让resolve函数创建一个总是拒绝的承诺吗?

3 个答案:

答案 0 :(得分:4)

不,让error1创建一个始终拒绝的承诺, 是您唯一的选择。

你可以利用.then有两个参数的事实:

.then(onSuccess, onFailure)

如果给出两个参数,那么onFailure 会在onSuccess中捕获失败,效果不佳。这通常是不受欢迎的,除了在这里,您可以使用此事实来分支您的决策树:

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

这就是你想要的。

  • 如果runArunB失败,则调用error1并停止链接。
  • 如果runCrunD失败,则调用error2并停止链接。

您也可以这样写:

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)
&#13;
<div id="div"></div>
&#13;
&#13;
&#13;

尝试修改this fiddle中的哪一个失败。

答案 1 :(得分:1)

仅使用一个.catch()有什么问题?您可以在catch回调(if (error1) error1() else if (error2) error2()...)中进行错误分类。您抛出的Error对象可以包含一条消息和一个名称(可能是您需要的类型,例如,RunCError&#39;)。

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...
}

答案 2 :(得分:0)

我只是偶然发现了同样的问题,到目前为止我的解决方案是明确调用{j} bin中的reject中的catchhttps://jsbin.com/yaqicikaza/edit?js,console

代码段

&#13;
&#13;
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
&#13;
&#13;
&#13;