打破承诺链和呼叫基于在链的步骤的函数,其中它被分解(拒绝) [英] Break promise chain and call a function based on the step in the chain where it is broken (rejected)

查看:191
本文介绍了打破承诺链和呼叫基于在链的步骤的函数,其中它被分解(拒绝)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:

要帮助这个职位的未来观众,我创建的 这个演示pluma的回答的。

问:

我的目标似乎相当简单。

 步骤(1)
  。然后(函数(){
    返回步骤(2);
  },函数(){
    stepError(1);
    返回$ q.reject();
  })
  。然后(函数(){  },函数(){
    stepError(2);
  });  功能步(N){
    变种推迟= $ q.defer();
    //失败的第1步
    (N === 1)? deferred.reject():deferred.resolve();
    返回deferred.promise;
  }
  功能stepError(N){
    的console.log(N);
  }

这里的问题是,如果我失败在步骤1中,既 stepError(1) stepError(2)被解雇。如果我不去收益$ q.reject 然后 stepError(2)不会被解雇,但步骤(2)会,我明白了。我已经完成但我想要做的一切。

我怎样写的承诺,这样我可以呼吁拒绝功能,而无需调用所有功能在错误链?还是有另一种方式来做到这一点?

这里有一个现场演示 因此你的东西的工作。

更新:

我的样的已经解决了它。在这里,我捉在链的末端误差和数据传递到拒绝(数据),这样我就知道错误函数来处理什么问题。这实际上是因为我不想依赖于数据不符合我的要求。这将是瘸腿的,但对我来说这将是更清洁的错误回调传递给函数,而不是依赖于返回的数据来决定该怎么做。

住在这里的演示(点击进入)。

 步骤(1)
  。然后(函数(){
    返回步骤(2);
  })
  。然后(函数(){
    返回步骤(3);
  })
  。然后(假的,
    功能(X){
      stepError(X);
    }
  );
  功能步(N){
    的console.log('步骤'+ N);
    变种推迟= $ q.defer();
    (N === 1)? deferred.reject(N):deferred.resolve(N);
    返回deferred.promise;
  }
  功能stepError(N){
    的console.log('错误'+ N);
  }


解决方案

按照预期的code不工作的原因是,它实际上是做一些从你认为它的不同。

让我们假设你有类似如下:

 的StepOne()
。然后(stepTwo,handleErrorOne)
。然后(stepThree,handleErrorTwo)
。然后(NULL,handleErrorThree);

要更好地理解所发生的事情,让我们pretend这是同步的code与尝试 / 块:

  {尝试
    尝试{
        尝试{
            VAR一个=的StepOne();
        }赶上(E1){
            一个= handleErrorOne(E1);
        }
        变种B = stepTwo(一);
    }赶上(E2){
        B = handleErrorTwo(E2);
    }
    变种C = stepThree(B);
}赶上(E3){
    C = handleErrorThree(E3);
}

onRejected 处理器(的第二个参数,那么)本质上是一种纠错机制(如块)。如果错误在 handleErrorOne 抛出,将被下一个catch块捕获(赶上(E2)),等

这显然不是你的本意。

比方说,我们希望整个分辨率链失败,无论什么不顺心:

 的StepOne()
。然后(函数(){
    返回stepTwo(一)。然后(NULL,handleErrorTwo);
},handleErrorOne)
。然后(功能(B){
    返回stepThree(B)。然后(NULL,handleErrorThree);
});

请注意:我们可以离开 handleErrorOne 它在哪里,因为如果的StepOne 拒绝它只会被调用(它在链中的第一个功能,所以我们知道,如果链条在这一点拒绝,那只能是因为该功能的承诺)。

重要的变化是,对于其他功能的错误处理不是主要的诺言链的一部分。相反,每个步骤都有其自己的子链具有 onRejected 如果步骤被拒绝(但不能由主链直接到达),其仅调用。

这部作品的原因是这两个 onFulfilled onRejected 是可选参数然后方法。如果承诺得到满足(即解决)和下然后链中的不具有 onFulfilled 处理程序,环比将继续下去,直到有一个这样的处理程序。

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

 的StepOne()。然后(stepTwo,handleErrorOne)
StepOne扩增()。然后(NULL,handleErrorOne)。然后(stepTwo)

但是下面一行的的等同于上述两种:

 的StepOne()。然后(stepTwo)。然后(NULL,handleErrorOne)

角的承诺库 $ Q 基于kriskowal的问:库(其中有一个更丰富的API,而是包含一切你可以在 $ q )。 Q的 API文档在GitHub上可以证明是有用的。 Q实现href=\"http://promises-aplus.github.io/promises-spec/\">少辉/ A +规格中的然后和承诺解析行为工作的。

编辑:

也请记住,如果你想摆脱你的错误处理程序链,它需要返回一个拒绝承诺或抛出一个错误(这将被自动捕获并包裹在被拒绝的承诺)。如果你不回一个承诺,然后包装在你下决心承诺的返回值。

这意味着,如果你不返回任何东西,你有效地返回该值的解决承诺未定义

Update:

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

Question:

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

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.

Update:

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.

Live demo here (click).

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.

Let's say you have something like the following:

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

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

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.

This is obviously not what you intended.

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

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).

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).

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'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.

EDIT:

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.

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

这篇关于打破承诺链和呼叫基于在链的步骤的函数,其中它被分解(拒绝)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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