221

I had a look at the bluebird promise FAQ, in which it mentions that .then(success, fail) is an antipattern. I don't quite understand its explanation as for the try and catch. What's wrong with the following?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

It seems that the example is suggesting the following to be the correct way.

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

What's the difference?

4

7 回答 7

247

有什么不同?

.then()调用将返回一个 Promise,如果回调抛出错误,该 Promise 将被拒绝。这意味着,当您的成功logger失败时,错误将传递给以下.catch()回调,但不会传递给fail旁边的回调success

这是一个控制流程图

带有两个参数的 then 控制流程图 then catch 链的控制流程图

用同步代码表示:

// 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 的解释

争论是,通常,您希望在处理的每个步骤中捕获错误,并且您不应该在链中使用它。期望您只有一个最终处理程序来处理所有错误 - 而当您使用“反模式”时,某些 then-callbacks 中的错误不会被处理。

然而,这种模式实际上非常有用:当您想要处理恰好在这一步中发生的错误,并且您想要在没有发生错误时做一些完全不同的事情 - 即当错误不可恢复时。请注意,这是分支您的控制流。当然,有时这是需要的。


以下有什么问题?

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()这个。

于 2014-07-09T20:35:02.617 回答
42

两者并不完全相同。不同之处在于第一个示例不会捕获success处理程序中引发的异常。因此,如果您的方法应该只返回已解决的承诺,通常情况下,您需要一个尾随catch处理程序(或另一个then带有空success参数的处理程序)。当然,您的then处理程序可能没有做任何可能失败的事情,在这种情况下,使用一个 2 参数then就可以了。

但是我相信您链接到的文本的重点是,then它在链接一堆异步步骤的能力方面与回调相比最有用,当您实际执行此操作时,2 参数形式的thensubtly 的行为并不像预期的那样, 出于上述原因。在中链使用时尤其违反直觉。

作为一个做过很多复杂的异步工作并且碰到这样的角落的人,我不想承认,我真的建议避免这种反模式并使用单独的处理程序方法。

于 2014-07-09T20:30:18.867 回答
18

通过查看两者的优点和缺点,我们可以对哪种情况适合进行计算猜测。这是实现 Promise 的两种主要方法。两者都有它的优点和缺点

捕捉方法

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

优点

  1. 所有错误都由一个 catch 块处理。
  2. 甚至在 then 块中捕获任何异常。
  3. 链接多个成功回调

缺点

  1. 在链接的情况下,很难显示不同的错误消息。

成功/错误方法

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

优点

  1. 您可以获得细粒度的错误控制。
  2. 您可以为各种类型的错误(如 db 错误、500 错误等)提供通用错误处理功能。

缺点

  1. catch如果您希望处理成功回调引发的错误,您仍然需要另一个
于 2016-03-20T14:55:26.103 回答
2

简单解释:

在 ES2018 中

当使用参数 onRejected 调用 catch 方法时,将执行以下步骤:

  1. 让 promise 成为 this 值。
  2. 返回 ?调用(promise, "then", « undefined, onRejected »)。

这意味着:

promise.then(f1).catch(f2)

等于

promise.then(f1).then(undefiend, f2)
于 2018-11-17T04:34:28.713 回答
1

使用.then().catch()允许您启用完成工作流所需的Promise Chaining 。您可能需要从数据库中读取一些信息,然后您想将其传递给异步 API,然后您想操作响应。您可能希望将响应推送回数据库。用您的概念处理所有这些工作流程是可行的,但很难管理。更好的解决方案是then().then().then().then().catch()在一次捕获中接收所有错误并让您保持代码的可维护性

于 2019-05-02T20:25:47.720 回答
1

在 promise 上使用then()catch()帮助链接成功和失败处理程序。catch()根据返回的承诺工作then()。它处理,

  1. 如果承诺被拒绝。参见图片中的#3
  2. 如果 then() 的成功处理程序中发生错误,则在下面的第 4 到第 7 行之间。参见图片中的#2.a(失败回调then()不处理此问题。)
  3. 如果 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()调用。注意图片中的#3 到. 当第 8 行和第 9 行中的处理程序未定义时调用它。catch()then()catch()

这是有道理的,因为then()如果回调正在处理它,则返回的 promise 不会有错误。

于 2019-09-15T18:30:08.530 回答
-2

代替言语,好榜样。以下代码(如果第一个承诺已解决):

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'); }
)
于 2017-12-28T16:37:08.800 回答