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

以干净的方式打破javascript承诺链,javascript,promise,Javascript,Promise,我试图将承诺连成链条,这样,如果一个承诺被拒绝,链条就会断裂。我遵循了a的思路,并试图将其应用于本地承诺,但我认为我误解了事情的运作方式 下面是我如何重写代码的: Promise.resolve() .then(function() { return step(1) .then(null, function() { stepError(1); }); }) .then(func

我试图将承诺连成链条,这样,如果一个承诺被拒绝,链条就会断裂。我遵循了a的思路,并试图将其应用于本地承诺,但我认为我误解了事情的运作方式

下面是我如何重写代码的:

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)返回被拒绝的承诺时,将按预期执行步骤错误(2)。但是由于它返回Promise.reject(2),下一步中的函数就不应该执行,而且由于最后没有catch,步骤2中被拒绝的承诺似乎会被转发,直到它退出链为止,因为它没有找到任何处理程序

我错过了什么

下面是一个可以使用的JSFIDLE:

在我看来,第二步应该打破这个链条

是的,但你不小心把拒绝变成了解决方案

关于承诺的关键是,对
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);
…或者您可以
在回调中抛出
,这会自动变成拒绝

未处理的拒绝警告是由以下事实引起的:
stepError
中没有任何内容会消耗拒绝


下面是一个返回
stepError
结果的示例:

Promise.resolve()
.然后(函数(){
返回步骤(1)
.then(null,函数(){
return stepError(1);//添加了“return”`
});
})
.然后(函数(){
返回步骤(2)
.then(null,函数(){
return stepError(2);//添加了“return”`
});
})
.然后(函数(){
返回步骤(3)
.then(null,函数(){
return stepError(3);//添加了“return”`
});
});
功能步骤(n){
console.log('步骤'+n);
返回(n==2)?承诺。拒绝(n):承诺。解决(n);
}
函数步进误差(n){
console.log('Error'+n);
返回承诺。拒绝(n);

}
正如@T.J.Crowder所说,您忘记了
返回错误处理程序的结果(或从中抛出
)。要解决这个问题,我建议您选择其中一种

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));
});