捕获之前和之后的位置
Placement of catch BEFORE and AFTER then
我无法理解将 .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);
});
每个函数的行为如下,如果数字为 <0
,则测试 1 失败;如果数字为 > 10
,则测试 2 失败;如果数字不是 100
,则测试 3 失败。在这种情况下,test2 只是失败了。
我尝试 运行 并使 test2Async 失败,然后 BEFORE 和 AFTER 的行为方式相同并且不执行 test3Async。有人可以向我解释将 catch 放置在不同位置的主要区别吗?
在每个函数中我console.log('Running test X')
为了检查它是否被执行。
这个问题的出现是因为我之前发布的帖子 。我认为这是一个不同的问题,值得发布另一个主题。
所以,基本上你是在问这两者之间的区别是什么(其中 p
是从以前的一些代码创建的承诺):
return p.then(...).catch(...);
和
return p.catch(...).then(...);
当 p 解析或拒绝时存在差异,但这些差异是否重要取决于 .then()
或 .catch()
处理程序中的代码。
当 p
结算时会发生什么:
在第一个方案中,当p
解析时,调用.then()
处理程序。如果 .then()
处理程序 return 是一个值或另一个最终解决的承诺,那么 .catch()
处理程序将被跳过。但是,如果 .then()
处理程序抛出或 return 一个最终拒绝的承诺,那么 .catch()
处理程序将执行原始承诺 p
中的拒绝,但也会.then()
处理程序中发生的错误。
在第二种方案中,当p
解析时,调用.then()
处理程序。如果该 .then()
处理程序抛出或 return 最终拒绝的承诺,则 .catch()
处理程序无法捕获它,因为它在链中位于它之前。
所以,这就是差异#1。如果 .catch()
处理程序是 AFTER,那么它也可以捕获 .then()
处理程序内部的错误。
当 p
拒绝时会发生什么:
现在,在第一个方案中,如果 promise p
被拒绝,则 .then()
处理程序将被跳过,.catch()
处理程序将按您预期的那样被调用。您在 .catch()
处理程序中所做的决定了最终结果是 return。如果您只是 return 来自 .catch()
处理程序的值或 return 最终解决的承诺,那么承诺链会切换到已解决状态,因为您“处理”了错误并且 return正常。如果您在 .catch()
处理程序中抛出或 return 一个被拒绝的承诺,那么 returned 承诺将保持被拒绝状态。
在第二种方案中,如果承诺 p
拒绝,则调用 .catch()
处理程序。如果您 return 一个正常值或最终从 .catch()
处理程序解决的承诺(因此“处理”错误),则承诺链切换到已解决状态和 .then()
处理程序.catch()
之后会被调用。
这就是差异#2。如果 .catch()
处理程序是 BEFORE,那么它可以处理错误并允许 .then()
处理程序仍然被调用。
何时使用哪个:
如果您只需要一个 .catch()
处理程序可以捕获原始承诺 p
或 .then()
处理程序中的错误以及来自 [=13] 的拒绝,请使用第一个方案=] 应该跳过 .then()
处理程序。
如果您希望能够捕获原始承诺中的错误,请使用第二种方案 p
并且可能(取决于条件)允许承诺链继续解决,从而执行 .then()
处理程序。
另一个选项
还有一个选项可以使用两个回调,您可以将其传递给 .then()
,如:
p.then(fn1, fn2)
这保证只会调用 fn1
或 fn2
之一。如果 p
解析,那么 fn1
将被调用。如果 p
拒绝,则 fn2
将被调用。 fn1
中的任何结果变化都不会使 fn2
被跟注,反之亦然。所以,如果你想绝对确保只调用你的两个处理程序中的一个,而不管处理程序本身发生了什么,那么你可以使用 p.then(fn1, fn2)
.
非常好,但我认为添加类似的同步代码是个好主意。
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()
将被调用。
我无法理解将 .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);
});
每个函数的行为如下,如果数字为 <0
,则测试 1 失败;如果数字为 > 10
,则测试 2 失败;如果数字不是 100
,则测试 3 失败。在这种情况下,test2 只是失败了。
我尝试 运行 并使 test2Async 失败,然后 BEFORE 和 AFTER 的行为方式相同并且不执行 test3Async。有人可以向我解释将 catch 放置在不同位置的主要区别吗?
在每个函数中我console.log('Running test X')
为了检查它是否被执行。
这个问题的出现是因为我之前发布的帖子
所以,基本上你是在问这两者之间的区别是什么(其中 p
是从以前的一些代码创建的承诺):
return p.then(...).catch(...);
和
return p.catch(...).then(...);
当 p 解析或拒绝时存在差异,但这些差异是否重要取决于 .then()
或 .catch()
处理程序中的代码。
当 p
结算时会发生什么:
在第一个方案中,当p
解析时,调用.then()
处理程序。如果 .then()
处理程序 return 是一个值或另一个最终解决的承诺,那么 .catch()
处理程序将被跳过。但是,如果 .then()
处理程序抛出或 return 一个最终拒绝的承诺,那么 .catch()
处理程序将执行原始承诺 p
中的拒绝,但也会.then()
处理程序中发生的错误。
在第二种方案中,当p
解析时,调用.then()
处理程序。如果该 .then()
处理程序抛出或 return 最终拒绝的承诺,则 .catch()
处理程序无法捕获它,因为它在链中位于它之前。
所以,这就是差异#1。如果 .catch()
处理程序是 AFTER,那么它也可以捕获 .then()
处理程序内部的错误。
当 p
拒绝时会发生什么:
现在,在第一个方案中,如果 promise p
被拒绝,则 .then()
处理程序将被跳过,.catch()
处理程序将按您预期的那样被调用。您在 .catch()
处理程序中所做的决定了最终结果是 return。如果您只是 return 来自 .catch()
处理程序的值或 return 最终解决的承诺,那么承诺链会切换到已解决状态,因为您“处理”了错误并且 return正常。如果您在 .catch()
处理程序中抛出或 return 一个被拒绝的承诺,那么 returned 承诺将保持被拒绝状态。
在第二种方案中,如果承诺 p
拒绝,则调用 .catch()
处理程序。如果您 return 一个正常值或最终从 .catch()
处理程序解决的承诺(因此“处理”错误),则承诺链切换到已解决状态和 .then()
处理程序.catch()
之后会被调用。
这就是差异#2。如果 .catch()
处理程序是 BEFORE,那么它可以处理错误并允许 .then()
处理程序仍然被调用。
何时使用哪个:
如果您只需要一个 .catch()
处理程序可以捕获原始承诺 p
或 .then()
处理程序中的错误以及来自 [=13] 的拒绝,请使用第一个方案=] 应该跳过 .then()
处理程序。
如果您希望能够捕获原始承诺中的错误,请使用第二种方案 p
并且可能(取决于条件)允许承诺链继续解决,从而执行 .then()
处理程序。
另一个选项
还有一个选项可以使用两个回调,您可以将其传递给 .then()
,如:
p.then(fn1, fn2)
这保证只会调用 fn1
或 fn2
之一。如果 p
解析,那么 fn1
将被调用。如果 p
拒绝,则 fn2
将被调用。 fn1
中的任何结果变化都不会使 fn2
被跟注,反之亦然。所以,如果你想绝对确保只调用你的两个处理程序中的一个,而不管处理程序本身发生了什么,那么你可以使用 p.then(fn1, fn2)
.
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()
将被调用。