我无法理解将.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?之前的帖子。我认为这是一个不同的问题,值得发布另一个主题。
答案 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)
这可以保证只调用fn1
或fn2
中的一个。如果p
结算,则会调用fn1
。如果p
拒绝,则会调用fn2
。 fn1
中的结果没有变化可以使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()
。