首页 文章

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

提问于
浏览
9

我试图链接承诺,以便如果一个承诺被拒绝,链将破裂 . 我跟着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

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

    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”应该在同一水平上 .

  • 12

    正如@ 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));
    });
    
  • 1

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

    它会,但你不小心将拒绝转换为决议 .

    关于promises的关键是每次对 then 的调用都会创建一个 new promise,它会根据 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 结果的示例:

    Promise.resolve()
        .then(function() {
            return step(1)
                .then(null, function() {
                    return stepError(1); // Added `return`
                });
        })
        .then(function() {
            return step(2)
                .then(null, function() {
                    return stepError(2); // Added `return`
                });
        })
        .then(function() {
            return step(3)
                .then(null, function() {
                    return stepError(3); // Added `return`
                });
        });
    
    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);
    }
    

相关问题