以干净的方式打破javascript承诺链

时间:2016-12-11 11:16:59

标签: javascript promise

我正在尝试将承诺链接起来,以便如果一个承诺被拒绝,链将会破裂。我跟着previous SO question的引导并尝试将其应用于原生承诺,但我认为我误解了事情的运作方式。

以下是我重写代码的方法:

Promise.resolve()
    .then(function() {
        return step(1)
            .then(null, function() {
                stepError(1);
            });
    })
    .then(function() {
        return step(2)
            .then(null, function() {
                stepError(2);
            });
    })
    .then(function() {
        return step(3)
            .then(null, function() {
                stepError(3);
            });
    });

function step(n) {
    console.log('Step '+n);
    return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
}

function stepError(n) {
    console.log('Error '+n);
    return Promise.reject(n);
}

上述代码的输出是:

Step 1
Step 2
Error 2
Step 3
[UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 2]

根据我的理解,第2步应该打破链条,不应该执行第3步。当步骤(2)返回被拒绝的promise时,stepError(2)按预期执行。但是因为它返回Promise.reject(2),所以下一个函数不应该被执行,并且因为最后没有catch,所以步骤2的被拒绝的承诺似乎 - 正如预期的那样 - 被转发,直到它退出因为它没有找到任何处理程序。

我在这里缺少什么?

这是一个可以玩的JSFiddle:https://jsfiddle.net/6p4t9xyk/

3 个答案:

答案 0 :(得分:12)

  

根据我的理解,第2步应该打破链条......

,但你不小心将拒绝转换为了解决方案。

关于承诺的关键是每次调用TransactionListener都会创建一个承诺,根据then回调的内容进行解析/拒绝,以及回调处理拒绝将拒绝转换为分辨率,除非故意不这样做。

所以这里:

then

这样你就可以使用错误处理程序来补偿错误。

由于return step(2) .then(null, function() { // This handler converts the stepError(2); // rejection into a resolution }); // with the value `undefined` 会返回拒绝,您只需添加stepError即可继续拒绝:

return

...或者,完全删除该处理程序:

return step(2)
    .then(null, function() {
        return stepError(2);  // Added `return`
    });

...或者您可以在回调中return step(2); ,这会自动变成拒绝。

未处理的拒绝警告是由于没有消耗throw的拒绝而引起的。

以下是返回stepError的结果的示例:

stepError

答案 1 :(得分:2)

看起来你过分复杂了。怎么样:

function step(n) {
    console.log('Step '+n);
    return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
}

function stepError(n) {
    console.log('Error '+n);
}

Promise.resolve()
    .then(() => step(1))
    .then(() => step(2))
    .then(() => step(3)) // never here
    .catch(stepError);

通常,“缩进然后”是反模式。所有“thens”应该在同一水平上。

答案 2 :(得分:0)

正如@ T.J.Crowder所说,你忘了return错误处理程序的结果(或throw来自它)。为了解决这个问题,我建议你做一下

function withStepError(n, promise) {
    return promise.catch(function(err) {
        console.log('Error '+err+' from '+n);
        throw new Error("failed at "+n);
    });
}
Promise.resolve()
.then(function() {
    return withStepError(1, step(1));
})
.then(function() {
    return withStepError(2, step(2));
})
.then(function() {
    return withStepError(3, step(3));
});

function getStepError(n) {
    return function(err) {
        console.log('Error '+err+' from '+n);
        throw new Error("failed at "+n);
    };
}

Promise.resolve()
.then(function() {
    return step(1).catch(getStepError(1));
})
.then(function() {
    return step(2).catch(getStepError(2));
})
.then(function() {
    return step(3).catch(getStepError(3));
});