然后在之前和之后放置捕获物

Zan*_*nko 81 javascript node.js promise bluebird

我无法理解将.catchBEFORE和AFTER放在嵌套的promise中之间的区别.

备选方案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);
});
Run Code Online (Sandbox Code Playgroud)

备选方案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);
  });
Run Code Online (Sandbox Code Playgroud)

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

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

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

这个问题出现是因为我发布的上一个帖子如何将嵌套回调转换为promise?.我认为这是一个不同的问题,值得发布另一个主题.

jfr*_*d00 186

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

return p.then(...).catch(...);
Run Code Online (Sandbox Code Playgroud)

return p.catch(...).then(...);
Run Code Online (Sandbox Code Playgroud)

有差异要么当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().

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

何时使用:

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

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

另一种选择

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

 p.then(fn1, fn2)
Run Code Online (Sandbox Code Playgroud)

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

  • 问题是关于`.then()`和`.catch()`的顺序,你回答.另外,您提供了何时使用哪个订单的一些提示,我认为提及第三个选项是合适的,即将成功和错误处理程序传递给[.then()](https://developer.mozilla.org/ EN-US /文档/网络/的JavaScript /参考/ Global_Objects /无极/然后#参数).在这种情况下,最多将调用一个处理程序. (12认同)
  • @ArneHugo - 好建议.我补充道. (6认同)

aki*_*don 20

jfriend00的答案非常好,但我认为添加类似的同步代码是个好主意.

return p.then(...).catch(...);
Run Code Online (Sandbox Code Playgroud)

类似于同步:

try {
  iMightThrow() // like `p`
  then()
} catch (err) {
  handleCatch()
}
Run Code Online (Sandbox Code Playgroud)

如果iMightThrow()不扔,then()将被调用.如果它确实抛出(或者如果then()它自己抛出),那么handleCatch()将被调用.注意catch块如何无法控制是否then被调用.

另一方面,

return p.catch(...).then(...);
Run Code Online (Sandbox Code Playgroud)

类似于同步:

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

then()
Run Code Online (Sandbox Code Playgroud)

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

  • @82Tuskers,你确定吗?如果我将 `then()` 放在 `finally{...}` 中,即使 `handleCatch()` 抛出,它不会被错误地调用吗?请记住,我的目标是展示类似的同步代码,而不是建议处理异常的不同方式 (2认同)