打破承诺链并根据链中被打破(被拒绝)的步骤调用一个函数 [英] Break promise chain and call a function based on the step in the chain where it is broken (rejected)

查看:23
本文介绍了打破承诺链并根据链中被打破(被拒绝)的步骤调用一个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了帮助这篇文章的未来观众,我创建了这个 pluma 的回答演示.

To help future viewers of this post, I created this demo of pluma's answer.

我的目标似乎相当简单.

My goal seems fairly straightforward.

  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)stepError(2) 都会被触发.如果我不 return $q.reject 那么 stepError(2) 不会被触发,但是 step(2) 会,这我明白.除了我想要做的事情之外,我已经完成了所有事情.

The problem here is that if I fail on step 1, both stepError(1) AND stepError(2) are fired. If I don't return $q.reject then stepError(2) won't be fired, but step(2) will, which I understand. I've accomplished everything except what I'm trying to do.

如何编写承诺,以便在拒绝时调用函数,而不调用错误链中的所有函数?或者还有其他方法可以做到这一点吗?

How do I write promises so that I can call a function on rejection, without calling all of the functions in the error chain? Or is there another way to accomplish this?

这是一个现场演示所以你有一些工作与.

Here's a live demo so you've got something work with.

有点解决了它.在这里,我在链的末尾捕获错误并将数据传递给 reject(data) 以便我知道在错误函数中要处理什么问题.这实际上不符合我的要求,因为我不想依赖数据.这会很蹩脚,但在我的情况下,将错误回调传递给函数会更清晰,而不是依赖返回的数据来确定要做什么.

I kind of have solved it. Here, I am catching the error at the end of the chain and passing the data to reject(data) so that I will know what issue to handle in the error function. This actually doesn't meet my requirements because I don't want to depend on the data. It would be lame, but in my case it would be cleaner to pass an error callback to the function rather than to depend on the returned data to determine what to do.

现场演示(点击).

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

推荐答案

你的代码没有按预期工作的原因是它实际上做了一些与你想象的不同的事情.

The reason your code doesn't work as expected is that it's actually doing something different from what you think it does.

假设您有以下内容:

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

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

To better understand what's happening, let's pretend this is synchronous code with try/catch blocks:

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)) 捕获,依此类推.

The onRejected handler (the second argument of then) is essentially an error correction mechanism (like a catch block). If an error is thrown in handleErrorOne, it will be caught by the next catch block (catch(e2)), and so on.

这显然不是你想要的.

假设无论出现什么问题,我们都希望整个解析链都失败:

Let's say we want the entire resolution chain to fail no matter what goes wrong:

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

注意:我们可以将 handleErrorOne 留在原处,因为只有在 stepOne 拒绝时才会调用它(它是链中的第一个函数,所以我们知道如果此时链被拒绝,则只能是因为该函数的承诺).

Note: We can leave the handleErrorOne where it is, because it will only be invoked if stepOne rejects (it's the first function in the chain, so we know that if the chain is rejected at this point, it can only be because of that function's promise).

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

The important change is that the error handlers for the other functions are not part of the main promise chain. Instead, each step has its own "sub-chain" with an onRejected that is only called if the step was rejected (but can not be reached by the main chain directly).

这样做的原因是 onFulfilledonRejected 都是 then 方法的可选参数.如果一个承诺被履行(即已解决)并且链中的下一个 then 没有 onFulfilled 处理程序,则该链将继续直到有这样的处理程序.

The reason this works is that both onFulfilled and onRejected are optional arguments to the then method. If a promise is fulfilled (i.e. resolved) and the next then in the chain doesn't have an onFulfilled handler, the chain will continue until there is one with such a handler.

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

This means the following two lines are equivalent:

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

但是下面这行等同于上面的两行:

But the following line is not equivalent to the two above:

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

Angular 的 promise 库 $q 基于 kriskowal 的 Q 库(它具有更丰富的 API,但包含您可以在 $q).Q 在 GitHub 上的 API 文档 可能很有用.Q 实现了Promises/A+ 规范,其中详细介绍了然后 并且承诺解析行为完全正常.

Angular's promise library $q is based on kriskowal's Q library (which has a richer API, but contains everything you can find in $q). Q's API docs on GitHub could prove useful. Q implements the Promises/A+ spec, which goes into detail on how then and the promise resolution behaviour works exactly.

还要记住,如果您想在错误处理程序中跳出链,它需要返回一个被拒绝的承诺或抛出一个错误(将被捕获并自动包装在一个被拒绝的承诺中).如果您不返回承诺,then 会为您将返回值包装在解决承诺中.

Also keep in mind that if you want to break out of the chain in your error handler, it needs to return a rejected promise or throw an Error (which will be caught and wrapped in a rejected promise automatically). If you don't return a promise, then wraps the return value in a resolve promise for you.

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

This means that if you don't return anything, you are effectively returning a resolved promise for the value undefined.

这篇关于打破承诺链并根据链中被打破(被拒绝)的步骤调用一个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆