小编典典

断开promise链,并根据该链中被破坏(被拒绝)的步骤调用函数

javascript

更新:

为了帮助以后的读者,我创建了pluma’s Answer的此演示。

题:

我的目标似乎很简单。

  step(1)
  .then(function() {
    return step(2);
  }, function() {
    stepError(1);
    return $q.reject();
  })
  .then(function() {

  }, function() {
    stepError(2);
  });

  function step(n) {
    var deferred = $q.defer();
    //fail on step 1
    (n === 1) ? deferred.reject() : deferred.resolve();
    return deferred.promise;
  }
  function stepError(n) {
    console.log(n); 
  }

这里的问题是,如果我在步骤1上失败,则两个stepError(1)AND都会stepError(2)被触发。如果我不return $q.reject那么stepError(2)就不会被解雇,但step(2)会,我明白了。除了我想做的以外,我已经完成了所有工作。

如何编写promise,以便我可以在拒绝时调用函数,而无需调用错误链中的所有函数?还是有另一种方法可以做到这一点?

更新:

有点
解决了。在这里,我在链的末尾捕获错误,并将数据传递给reject(data)我,以便我知道在错误函数中要处理的问题。这实际上不符合我的要求,因为我不想依赖数据。会很,脚,但就我而言,将错误回调传递给函数将比使用返回的数据来确定操作要干净得多。

step(1)
  .then(function() {
    return step(2);
  })
  .then(function() {
    return step(3);
  })
  .then(false, 
    function(x) {
      stepError(x);
    }
  );
  function step(n) {
    console.log('Step '+n);
    var deferred = $q.defer();
    (n === 1) ? deferred.reject(n) : deferred.resolve(n);
    return deferred.promise;
  }
  function stepError(n) {
    console.log('Error '+n); 
  }

阅读 402

收藏
2020-05-01

共1个答案

小编典典

您的代码无法按预期工作的原因是它实际上在做与您认为的有所不同的事情。

假设您有以下内容:

stepOne()
.then(stepTwo, handleErrorOne)
.then(stepThree, handleErrorTwo)
.then(null, handleErrorThree);

为了更好地了解正在发生的事情,让我们假设这是带有try/ catch块的同步代码:

try {
    try {
        try {
            var a = stepOne();
        } catch(e1) {
            a = handleErrorOne(e1);
        }
        var b = stepTwo(a);
    } catch(e2) {
        b = handleErrorTwo(e2);
    }
    var c = stepThree(b);
} catch(e3) {
    c = handleErrorThree(e3);
}

onRejected处理程序(的第二个参数then)本质上是一个纠错机制(如catch块)。如果抛出错误handleErrorOne,它将被下一个catch块(catch(e2))捕获,依此类推。

这显然不是您想要的。

假设无论发生什么问题,我们都希望整个解决方案链失败:

stepOne()
.then(function(a) {
    return stepTwo(a).then(null, handleErrorTwo);
}, handleErrorOne)
.then(function(b) {
    return stepThree(b).then(null, handleErrorThree);
});

注意:我们可以保留handleErrorOne它的位置,因为只有在stepOne拒绝时才会调用它(它是链中的第一个函数,因此我们知道如果链在此刻被拒绝,那只能是由于该函数的诺言而已)

重要的变化是其他功能的错误处理程序不属于主要的Promise链。相反,每个步骤都有其自己的“子链”,onRejected只有在该步骤被拒绝(但主链无法直接到达)时才调用该子链。

这样做的原因是onFulfilledonRejected都是then方法的可选参数。如果兑现了一个承诺(即已解决),并且then链中的下一个没有onFulfilled处理程序,则链将继续进行,直到有一个具有此类处理程序的处理程序为止。

这意味着以下两行是等效的:

stepOne().then(stepTwo, handleErrorOne)
stepOne().then(null, handleErrorOne).then(stepTwo)

但是以下行 并不 等同于以上两行:

stepOne().then(stepTwo).then(null, handleErrorOne)

Angular的promise库$q基于kriskowal的Q库(具有更丰富的API,但包含您可以在中找到的所有内容$q)。GitHub上的Q的API文档可能很有用。Q实现了Promises / A +规范,该规范详细介绍了如何then以及如何实现承诺解决行为。

编辑:

还要记住,如果您想打破错误处理程序中的链条,它需要返回被拒绝的承诺或引发错误(将被捕获并自动包裹在被拒绝的承诺中)。如果您不返回承诺,then则将返回值包装在为您解决的承诺中。

这意味着,如果您不返回任何内容,则实际上是在返回一个已解析的value承诺undefined

2020-05-01