渔获物在接前和后放置解析以下情况时会发生什么情况:p拒绝时会发生什么:p何时使用哪种:另一种选择

2022-08-30 02:37:28

我很难理解将之前和之后放在嵌套承诺中的区别。.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);
  });

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

我试图运行并使test2Async失败,然后之前和之后的行为方式相同,那就是不执行test3Async。有人可以向我解释将渔获物放在不同地方的主要区别吗?

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

这个问题是由于我发布的上一个线程而引起的 如何将嵌套回调转换为承诺?.我认为这是一个不同的问题,值得发布另一个主题。


答案 1

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

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

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

当 p 解析或拒绝时存在差异,但这些差异是否重要取决于 or 处理程序内部的代码的作用。.then().catch()

解析以下情况时会发生什么情况:p

在第一个方案中,解析时,将调用处理程序。如果该处理程序返回最终解析的值或其他承诺,则跳过该处理程序。但是,如果处理程序抛出或返回最终拒绝的承诺,则处理程序将执行原始承诺中的拒绝,以及处理程序中发生的错误。p.then().then().catch().then().catch()p.then()

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

所以,这就是区别#1。如果 .catch() 处理程序是 AFTER,则它还可以捕获 .then() 处理程序中的错误。

拒绝时会发生什么:p

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

在第二个方案中,如果承诺被拒绝,则调用处理程序。如果返回一个普通值或最终从处理程序解析的承诺(从而“处理”错误),则承诺链将切换到已解决的状态,并在调用 之后切换到处理程序。p.catch().catch().then().catch()

这就是区别#2。如果 .catch() 处理程序是 BEFORE,则它可以处理错误并允许 .then() 处理程序仍然被调用。

何时使用哪种:

如果只需要一个可以在原始 promise 或处理程序中捕获错误的处理程序,并且拒绝应跳过该处理程序,请使用第一个方案。.catch()p.then()p.then()

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

另一种选择

还有一个选项可以使用这两个回调,您可以将其传递给,如下所示:.then()

 p.then(fn1, fn2)

这保证了只有一个或将永远被调用。如果解析,则将调用。如果拒绝,则将被调用。任何结果的变化都不能使被召唤,反之亦然。因此,如果您想绝对确保只调用两个处理程序中的一个,而不管处理程序本身发生了什么,那么您可以使用 。fn1fn2pfn1pfn2fn1fn2p.then(fn1, fn2)


答案 2

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

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

类似于同步:

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

如果不抛出,将被调用。如果它确实抛出(或者如果它自己抛出),则将被调用。请注意,该块无法控制是否被调用。iMightThrow()then()then()handleCatch()catchthen

另一方面

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

类似于同步:

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

then()

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