【问题标题】:Is there any way to chain promises while handling errors as if promises were nested?有没有办法在处理错误时链接承诺,就像承诺是嵌套的一样?
【发布时间】:2015-12-21 02:21:29
【问题描述】:

我有以下代码 (http://jsfiddle.net/tj1eo86s/):

promise(1).then(function() {
    console.log("OK1");
    promise(2).then(function() {
        console.log("OK2");
        promise(3).then(function() {
            console.log("OK3");
        }, function() {
            console.log("KO3");
        });
    }, function() {
        console.log("KO2");
    });
}, function() {
    console.log("KO1");
});

如果 promise(2) 被拒绝,输出将是:

OK1
KO2

如何在链接 Promise 时获得相同的行为?

我尝试过 (http://jsfiddle.net/7goh0ds9/):

promise(1)
.then(function() {
    console.log("OK1");
    return promise(2);
}, function() {
    console.log("KO1");
})
.then(function() {
    console.log("OK2");
    return promise(3);
}, function() {
    console.log("KO2");
})
.then(function() {
    console.log("OK3");
}, function() {
    console.log("KO3");
});

但是输出是:

OK1
KO2
OK3

然后我尝试在错误回调中抛出错误(http://jsfiddle.net/cyx6mohy/):

promise(1)
.then(function() {
    console.log("OK1");
    return promise(2);
}, function() {
    console.log("KO1");
    throw "KO1";
})
.then(function() {
    console.log("OK2");
    return promise(3);
}, function() {
    console.log("KO2");
    throw "KO2";
})
.then(function() {
    console.log("OK3");
}, function() {
    console.log("KO3");
    throw "KO3";
});

但现在我有:

OK1
KO2
KO3

我实际上了解所有这些行为,但我一直无法找到一个解决方案来处理错误,就像嵌套承诺一样。

【问题讨论】:

  • 我不太明白你的问题到底是什么。嵌套是与链接不同的结构,因此很难弄清楚如何使一个结构在概念上与另一个结构具有相同的行为。当你得到一个被拒绝的承诺时,你完全可以控制接下来会发生什么。如果您处理拒绝,那么您从拒绝处理程序返回的任何内容都将成为延续值。如果你从拒绝处理程序中抛出或返回一个被拒绝的承诺,那么父承诺将被拒绝,并且链中的下一个拒绝处理程序将被调用。在下一条评论中继续...
  • 如果你处理了拒绝并且不抛出或返回被拒绝的承诺,那么链中的下一个成功处理程序将被调用。通过“处理”拒绝而不返回继续错误,您已经“处理”了错误并继续正常的成功处理。
  • @jfriend00 是的,谢谢你的解释,这也是我读到的(这就是为什么我说我实际上理解所有这些行为)。关键是我发现链式 Promise 比嵌套式 Promise 更具可读性和可维护性(尤其是当你有很多它们时),但嵌套式 Promise 的行为实际上符合我的需要。所以问题是:在链接 promise 时,如何处理错误,就像处理 promise 嵌套时一样。
  • 嗯,您的问题是通用的,“如何使链像嵌套一样工作”,通用的答案是您不能。它们不是相同的结构。如果您的问题确实是在使用这组链式 Promise 时发生此错误时如何获得此特定输出,那么可能会提供完全针对您的确切代码情况的答案。没有通用的答案。
  • @jfriend00 这就是我害怕的。但是“你不能”实际上是正确的答案,所以也许你可以将它添加为答案。

标签: javascript error-handling promise chaining


【解决方案1】:

您可以将索引作为参数拒绝,然后添加.catch 并在那里处理错误:

var breakOnPromise = 2;

function promise(i) {
    return new Promise(function(resolve, reject) {
        if (i == breakOnPromise) {
            reject(i); // pass index to catch
        } else {
            resolve();
        }
    });
}

promise(1).then(function() {
    console.log("OK1");
    return promise(2);
}).then(function() {
    console.log("OK2");
    return promise(3);
}).then(function() {
    console.log("OK3");
}).catch(function(i) {
    // This is just for your case,
    // but you could use an `if` statement
    var err = ["KO1", "KO2", "KO3"][i - 1];
    console.log(err);
});

【讨论】:

    【解决方案2】:

    如果您的问题是我一般如何使链接处理错误的方式与任意嵌套完全相同,那么答案是您不能以通用方式。链接是一种与任意嵌套完全不同的控制结构。

    您可以设计一个与链接具有基本相同行为的嵌套。或者,如果您想要在链接世界中模拟的嵌套结构中的特定错误处理行为,您“可能”能够在链接序列中使用适当的错误处理和控制流来实现这一点。请注意,我说“可能”是因为它完全取决于嵌套序列在做什么。您也可能无法使用纯链接来模拟它。

    如果您的问题是,当链中的特定承诺被拒绝时,我如何使这一系列链承诺生成此特定响应,那么这可能是可能的,但它将针对您的特定情况和期望的结果进行编码,而不是在一些通用的方法。

    基本上,有理由使用链接,有理由使用嵌套,也有理由使用两者的组合。和你一样,我更喜欢链接,因为控制流和可读性​​看起来更简单,所以我总是从这个结构开始,但在我的代码中肯定有时间我必须对某些操作使用嵌套(通常是因为分支决策或某些类型的所需错误处理)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 2015-06-20
      • 2020-04-11
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      相关资源
      最近更新 更多