提问人:user2127480 提问时间:7/10/2014 最后编辑:Sabito stands with Ukraineuser2127480 更新时间:12/29/2021 访问量:36079
什么时候 .then(success, fail) 被认为是 promise 的反模式?
When is .then(success, fail) considered an antipattern for promises?
问:
我看了一下 bluebird promise FAQ,其中提到 .then(success, fail)
是一个反模式。我不太明白它对 和 的解释。
以下有什么问题?try
catch
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
该示例似乎表明以下是正确的方法。
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
有什么区别?
答:
两者并不完全相同。不同之处在于,第一个示例不会捕获处理程序中引发的异常。因此,如果你的方法应该只返回已解析的 promise,就像通常的情况一样,你需要一个尾随处理程序(或者另一个带有空参数的处理程序)。当然,可能是您的处理程序没有执行任何可能失败的事情,在这种情况下,使用一个 2 参数可能没问题。success
catch
then
success
then
then
但我相信你链接到的文本的要点是,与回调相比,它最有用的是它能够链接一堆异步步骤,当你实际这样做时,由于上述原因,微妙的 2 参数形式的行为并不完全符合预期。当在链条中间使用时,这尤其违反直觉。then
then
作为一个做过很多复杂的异步工作并且遇到过这样的角落的人,我真的建议避免这种反模式,并使用单独的处理程序方法。
有什么区别?
该调用将返回一个承诺,如果回调引发错误,该承诺将被拒绝。这意味着,当您的成功失败时,错误将传递给下一个回调,但不会传递给旁边的回调。.then()
logger
.catch()
fail
success
下面是一个控制流程图:
要用同步代码表示它,请执行以下操作:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
第二个(类似于第一个参数 ),只有在没有发生异常的情况下才会执行。标记的块和语句感觉有点奇怪,这实际上是 python 的 try-except-else
用途(推荐阅读!log
.then()
break
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
记录器还将处理成功记录器调用的异常。catch
差异就这么多。
我不太明白它对尝试和捕获的解释
论点是,通常,您希望在处理的每个步骤中捕获错误,并且不应该在链中使用它。期望您只有一个处理所有错误的最终处理程序 - 而当您使用“反模式”时,某些当时的回调中的错误不会被处理。
但是,此模式实际上非常有用:当您想要处理在此步骤中发生的错误时,并且希望在没有发生错误时(即当错误不可恢复时)执行完全不同的事情时。请注意,这是对控制流的分支。当然,这有时是需要的。
以下有什么问题?
some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
你必须重复你的回调。你宁愿想要
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
您也可以考虑为此使用 .finally()。
评论
.catch
.done()
不是标准的一部分,是吗?至少 MDN 没有列出该方法。这将是有帮助的。
通过查看两者的优缺点,我们可以对哪种情况进行有计划的猜测。 这是实现承诺的两种主要方法。两者都有它的优点和缺点
捕获方法
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
优势
- 所有错误都由一个 catch 块处理。
- 甚至捕获 then 块中的任何异常。
- 链接多个成功回调
弊
- 在链接的情况下,很难显示不同的错误消息。
成功/错误方法
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
优势
- 您可以获得细粒度的错误控制。
- 您可以对各种类别的错误(如数据库错误,500错误等)具有常见的错误处理功能。
Disavantages
- 如果您希望处理成功回调引发的错误,您仍然需要另一个
catch
评论
代替言语,好榜样。以下代码(如果第一个 promise 已解决):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
等同于:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
但是,对于被拒绝的第一个承诺,这并不完全相同:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
评论
简单解释:
在 ES2018 中
当使用参数 onRejected 调用 catch 方法时, 采取以下步骤:
- 让 promise 成为这个值。
- 返回?Invoke(promise, “then”, « undefined, onRejected »)。
这意味着:
promise.then(f1).catch(f2)
等于
promise.then(f1).then(undefiend, f2)
使用可以启用完成工作流所需的 Promise Chaining。您可能需要从数据库中读取一些信息,然后将其传递给异步 API,然后需要操作响应。您可能希望将响应推送回数据库。用您的概念处理所有这些工作流程是可行的,但很难管理。更好的解决方案是,只需一次捕获即可接收所有错误,并让您保持代码的可维护性。.then().catch()
then().then().then().then().catch()
使用 和 帮助链上的成功和失败处理程序上的承诺。对 返回的 promise 起作用。它处理,then()
catch()
catch()
then()
- 如果承诺被拒绝。见图中的#3
- 如果在 then() 的成功处理程序中发生错误,则在下面的第 4 行到第 7 行之间。见图中的#2.a
(失败回调 on 不处理此问题。
then()
- 如果 then() 的失败处理程序发生错误,则下面的第 8 行。请参阅图片中的#3.b。
1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });
注意:很多时候,如果是 已经写好了。 编辑:仅当错误时才调用 未定义 handler in。注意 #3 在图片中 这。当第 # 8 行和第 9 行中的处理程序不是 定义。
catch()
reject()
catch()
then()
catch()
这是有道理的,因为如果回调正在处理它,则返回的 promise 不会出错。then()
评论
catch
评论
then().catch()
更具可读性,因为您不需要查找逗号并调查此回调是成功还是失败分支。.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
.then(function(res) { logger.log(res) }).catch( function(err) { logger.log(err) })
.catch
then
some_promise_call() .then(function fulfilled(res) { logger.log(res) }, function rejected(err) { logger.log(err) })