我看了蓝鸟诺言常见问题解答,其中提到.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) })
 


有什么区别?

评论

then()。catch()更具可读性,因为您无需查找逗号,而可以调查此回调是否成功或失败分支。

@KevinB:有很大的不同,请查看答案

@KrzysztofSafjanowski-被“看起来更好”的论点所破坏。完全错误!

注意:使用.catch时,您不知道是哪个步骤导致了问题-在最后一个步骤内还是在承诺链的其他位置。因此它确实有其自身的缺点。

我总是在promise .then()参数中添加函数名称以使其可读,即some_promise_call().then(function满载(res){logger.log(res)},函数rejected(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