断开承诺链,并根据链中该函数中断(拒绝)的步骤调用函数

2022-08-30 02:32:46

更新:

为了帮助这篇文章的未来观众,我创建了这个羽毛答案的演示

问题:

我的目标似乎相当简单。

  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上失败,两个AND都会被触发。如果我不这样做,那么就不会被解雇,但会被解雇,我理解这一点。我已经完成了一切,除了我想做的事情。stepError(1)stepError(2)return $q.rejectstepError(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); 
  }

答案 1

你的代码没有按预期工作的原因是,它实际上正在做一些与你认为它所做的事情不同的事情。

假设您有类似下面的内容:

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

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

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

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

这显然不是你的本意。

假设我们希望无论出现什么问题,整个分辨率链都会失败:

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

注意:我们可以将它保留在原来的位置,因为它只有在被拒绝时才会被调用(它是链中的第一个函数,所以我们知道,如果链在这一点上被拒绝,它只能是因为该函数的承诺)。handleErrorOnestepOne

重要的变化是其他函数的错误处理程序不是主承诺链的一部分。相反,每个步骤都有自己的“子链”,其中只有当步骤被拒绝时才调用(但主链无法直接到达)。onRejected

这有效的原因是两者都是该方法的可选参数。如果一个承诺已经实现(即已解析),并且链中的下一个没有处理程序,则该链将继续,直到有一个具有此类处理程序。onFulfilledonRejectedthenthenonFulfilled

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

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

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

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

Angular的承诺库基于kriskowal的库(它具有更丰富的API,但包含您可以在中找到的所有内容)。Q在GitHub上的API文档可能会被证明是有用的。Q 实现了 Promises/A+ 规范,该规范详细介绍了 Promise 解析行为如何以及承诺解析行为是否准确工作。$qQ$qthen

编辑:

还要记住,如果你想在错误处理程序中打破链条,它需要返回一个被拒绝的承诺或抛出一个错误(它将自动被捕获并包装在被拒绝的承诺中)。如果不返回承诺,则 将返回值包装在解析承诺中。then

这意味着,如果您不返回任何内容,则实际上返回了未定义的值的已解析 promise。


答案 2

派对有点晚了,但这个简单的解决方案对我有用:

function chainError(err) {
  return Promise.reject(err)
};

stepOne()
.then(stepTwo, chainError)
.then(stepThreee, chainError);

这使您可以打破链条。