然后在

时间:2017-02-02 21:59:37

标签: javascript node.js promise bluebird

我无法理解将.catch之前和之后放在嵌套的承诺中之间的区别。

备选方案1:

test1Async(10).then((res) => {
  return test2Async(22)
    .then((res) => {
      return test3Async(100);
    }).catch((err) => {
      throw "ERROR AFTER THEN";
    });
}).then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

备选方案2:

test1Async(10).then((res) => {
   return test2Async(22)
     .catch((err) => {
        throw "ERROR BEFORE THEN";
      })
      .then((res) => {
        return test3Async(100);
      });
  }).then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

每个函数的行为如下所示,如果number为<0 test1失败,则test1失败如果number为> 10则test1失败,如果number不是100,则test3失败。在这种情况下,test2只是失败了。

我试图运行并使test2Async失败,BEFORE和AFTER之后的行为方式相同,并且没有执行test3Async。有人可以向我解释将捕捞放在不同地方的主要区别吗?

在每个函数I console.log('Running test X')中检查它是否被执行。

出现这个问题是因为我发布了How to turn nested callback into promise?之前的帖子。我认为这是一个不同的问题,值得发布另一个主题。

2 个答案:

答案 0 :(得分:152)

所以,基本上你要问的是这两者之间有什么区别(p是从以前的代码创建的一个承诺):

return p.then(...).catch(...);

return p.catch(...).then(...);

p解析或拒绝时存在差异,但这些差异是否重要取决于.then().catch()处理程序中的代码是什么。

p结算时会发生什么:

在第一个方案中,当p解析时,调用.then()处理程序。如果.then()处理程序返回一个值或最终解析的另一个promise,则跳过.catch()处理程序。但是,如果.then()处理程序抛出或返回最终拒绝的promise,那么.catch()处理程序将对原始promise p中的拒绝执行,但也会发生错误在.then()处理程序中。

在第二个方案中,当p解析时,调用.then()处理程序。如果.then()处理程序抛出或返回最终拒绝的promise,则.catch()处理程序无法捕获它,因为它位于链中。

所以,差异是#1。如果.catch()处理程序是AFTER,那么它也可以在.then()处理程序中捕获错误。

p拒绝时会发生什么:

现在,在第一个方案中,如果promise p拒绝,则跳过.then()处理程序,并按照您的预期调用.catch()处理程序。您在.catch()处理程序中执行的操作将确定返回的内容作为最终结果。如果您只是从.catch()处理程序返回一个值或返回最终解析的promise,那么promise链会切换到已解析状态,因为您“处理”了错误并正常返回。如果您在.catch()处理程序中抛出或返回被拒绝的承诺,则返回的承诺将被拒绝。

在第二种方案中,如果promise p拒绝,则调用.catch()处理程序。如果返回正常值或最终从.catch()处理程序解析的promise(从而“处理”错误),则promise链将切换到已解析状态和.then()处理程序.catch()处理程序。 1}}将被调用。

这就是#2的差异。如果.catch()处理程序是BEFORE,那么它可以处理错误并允许.then()处理程序仍被调用。

何时使用:

如果您只想要一个.catch()处理程序可以捕获原始承诺p.then()处理程序中的错误以及来自p的拒绝,请使用第一个方案应该跳过.then()处理程序。

如果您希望能够捕获原始承诺p中的错误并且可能(取决于条件),请使用第二种方案,允许承诺链继续解析,从而执行.then()处理程序。

另一个选项

还有一个选项可以使用您可以传递给.then()的两个回调,如:

 p.then(fn1, fn2)

这可以保证只调用fn1fn2中的一个。如果p结算,则会调用fn1。如果p拒绝,则会调用fn2fn1中的结果没有变化可以使fn2被调用,反之亦然。因此,如果您想要确保只调用两个处理程序中的一个,而不管处理程序本身发生了什么,那么您可以使用p.then(fn1, fn2)

答案 1 :(得分:13)

jfriend00's answer非常好,但我认为添加类似的同步代码是个好主意。

return p.then(...).catch(...);

类似于同步:

try {
  iMightThrow() // like `p`
  then()
} catch (err) {
  handleCatch()
}

如果iMightThrow()没有投出,则会调用then()。如果它抛出(或then()本身抛出),则会调用handleCatch()。请注意catch块无法控制是否调用then

另一方面,

return p.catch(...).then(...);

类似于同步:

try {
  iMightThrow()
} catch (err) {
  handleCatch()
}

then()

在这种情况下,如果iMightThrow()没有投出,则会then()执行。如果它确实抛出,则最多handleCatch()决定是否调用then(),因为如果handleCatch()重新抛出,则不会调用then(),因为异常将被立即抛给来电者。如果handleCatch()可以优雅地处理问题,则会调用then()