.then(success, fail)
是反模式。我对试捕不甚了解。 以下内容有何问题?
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) })
有什么区别?
#1 楼
有什么区别?
.then()
调用将返回一个Promise,以防在回调引发错误时拒绝该Promise。这意味着,当您成功执行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);
}
第二个
log
(就像.then()
的第一个参数) )仅在没有异常发生的情况下执行。带标签的块和break
语句有点奇怪,这实际上是python拥有try-except-else
的功能(建议阅读!)。// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
catch
记录器还将处理异常来自成功记录器的呼叫。差异很大。
我不太理解它关于try and 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即使在成功函数内部也可以捕获错误。.我个人认为这非常错误,因为您最终得到一个错误输入点,该错误输入点可以得到多个来自多个动作的错误,但这是我的问题。无论如何-感谢您提供信息!您没有愿意分享的在线交流工具,所以我想问的更多吗? :P
–安德烈·波波夫(Andrey Popov)
2015年2月27日14:21在
我希望这里能给您更多的支持。绝对是该站点上重要Promise机械师的最佳解释之一。
–帕特里克·罗伯茨
18年2月2日在21:28
.done()不是标准的一部分,对吗?至少MDN没有列出该方法。这将是有帮助的。
– ygoe
19年3月31日在17:52
@ygoe确实。完成是Bluebird的事情,基本上是由then + unhandled-rejection检测弃用的。
–贝尔吉
19年3月31日在18:58
只是色盲的注释:图表没有意义:)
– Benny K
19年11月22日在7:28
#2 楼
两者并不完全相同。不同之处在于,第一个示例不会捕获success
处理程序中引发的异常。因此,如果您的方法(通常)只返回已解析的Promise,则需要一个尾随的catch
处理程序(或另一个带有空的then
参数的success
)。当然,可能是您的then
处理程序没有做任何可能会失败的事情,在这种情况下,使用一个2参数then
可能会很好。但是我相信您链接的文本的意思相对于回调,
then
在链接一系列异步步骤方面最有用,并且当您实际执行此操作时,由于上述原因,then
的2参数形式的表现也不理想。当在中间链中使用时,这特别有悖常理。使用单独的处理程序方法。#3 楼
通过查看两者的优缺点,我们可以对哪种情况适合进行估算。这是实现承诺的两种主要方法。两者都有其优缺点
捕获方法
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) })
/>
优点
您可以获得细粒度的错误控制。
对于各种错误,例如db错误,500错误等,您可以具有通用的错误处理功能。
破坏行为
如果您希望处理成功回调引发的错误,您仍然需要另一个
catch
评论
对于只需要使用日志文件调试生产问题的人,我更喜欢“成功/错误方法”,因为它可以创建因果错误链,该链可以记录在应用程序的出口边界。
– Shane Rowatt
16年7月7日在0:03
题。可以说我做了一个异步调用,该调用执行以下操作之一:1)成功返回(2xx状态码),2)未成功返回(4xx或5xx代码),但本身未被拒绝,3)或根本不返回(互联网连接已断开)。对于情况#1,将命中.then中的成功回调。对于案例2,点击.then中的错误回调。对于情况3,将调用.catch。这是正确的分析,对不对?情况2是最棘手的,从技术上讲4xx或5xx并不是拒绝,它仍然可以成功返回。因此,我们需要在.then内处理它。 ....我的理解正确吗?
–本杰明·霍夫曼(Benjamin Hoffman)
17年8月30日14:47
“对于情况2,命中.then中的错误回调。对于情况3,将调用.catch。这是正确的分析,对吗?” -提取就是这样的
– aWebDeveloper
17年3月3日在16:07
#4 楼
简单说明:在ES2018中
当使用参数onRejected调用catch方法时,将执行以下步骤:
请保证这是值。
返回?调用(承诺,“然后”,«未定义,onRejected»)。
表示:
promise.then(f1).catch(f2)
等于
promise.then(f1).then(undefiend, f2)
#5 楼
使用.then().catch()
可以启用实现工作流程所需的Promise Chaining。您可能需要从数据库中读取一些信息,然后将其传递给异步API,然后才能处理响应。您可能需要将响应推回数据库。用您的概念来处理所有这些工作流是可行的,但很难管理。更好的解决方案是then().then().then().then().catch()
,它一次捕获就接收所有错误,并让您保持代码的可维护性。 #6 楼
使用then()
和catch()
有助于按承诺链接成功和失败处理程序。 catch()
处理then()
返回的诺言。它处理如果诺言被拒绝。请参见图片中的#3
如果then()的成功处理程序中发生错误,则在下面的行号4至7之间。请参阅图片中的#2.a
(
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. });
注意:很多时候,可能未定义故障处理程序如果已经编写了
catch()
。
编辑:
reject()
仅在未定义catch()
中的错误处理程序的情况下才导致调用then()
。注意图片中的#3到catch()
。未定义第8行和第9行中的处理程序时调用它。 这是有道理的,因为由
then()
返回的promise如果进行回调时不会出错。评论
从数字3到catch回调的箭头似乎是错误的。
–贝尔吉
19-09-15在18:57
谢谢!如果在then()中定义了错误回调,则不会调用它(代码段中的第8行和第9行)。 #3调用两个箭头之一。这是有道理的,因为如果回调正在处理的话,那么then()返回的promise没有错误。编辑答案!
–VenCKi
19-09-15在19:33
#7 楼
代替言语,好榜样。以下代码(如果已解决第一个诺言): 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'); }
)
评论
这没有道理,您能删除这个答案吗?这会误导人并且分散正确答案的注意力。
–安迪·雷(Andy Ray)
18年5月15日在4:00
@AndyRay,这在实际应用中没有任何意义,但了解诺言的工作是有意义的。
–ktretyak
18年5月15日在8:12
评论
then()。catch()更具可读性,因为您无需查找逗号,而可以调查此回调是否成功或失败分支。@KevinB:有很大的不同,请查看答案
@KrzysztofSafjanowski-被“看起来更好”的论点所破坏。完全错误!
注意:使用.catch时,您不知道是哪个步骤导致了问题-在最后一个步骤内还是在承诺链的其他位置。因此它确实有其自身的缺点。
我总是在promise .then()参数中添加函数名称以使其可读,即some_promise_call().then(function满载(res){logger.log(res)},函数rejected(err){logger.log(err) })