捕获前后的放置

我有困难理解之间的区别,把 .catch之前和之后,然后在一个嵌套的承诺。

选择一:

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

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

我尝试运行 test2Async 并使其失败,然后在 BEFORE 和 AFTER 之后都以相同的方式执行,而这并不是在执行 test3Async。有人能给我解释一下在不同的地方放渔获物的主要区别吗?

在每个函数 I console.log('Running test X'),以检查它是否得到执行。

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

53532 次浏览

因此,基本上你会问这两者之间的区别是什么(其中 p是由以前的一些代码创建的承诺) :

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

还有

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

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

p解决问题时会发生什么:

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

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

这就是区别之一。如果 .catch()处理程序是 AFTER,那么它也可以捕获 .then()处理程序中的错误。

p拒绝时会发生什么:

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

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

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

何时使用:

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

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

另一个选择

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

 p.then(fn1, fn2)

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

Jfriend 00的回答 非常好,但是我认为添加类似的同步代码是一个好主意。

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()将被调用。