【问题标题】:JavaScript Promise: Reject handler vs catch [duplicate]JavaScript Promise:拒绝处理程序与捕获 [重复]
【发布时间】:2019-03-10 09:40:19
【问题描述】:

我遇到过多个应用程序,其中使用catch 优于rejectHandler。 例如: 喜欢

new Promise.then(resolveHandler).catch()

而不是

new Promise().then(resolveHandler, rejectHandler).catch()

这有什么特别的原因吗??

我找到了

new Promise().then(resolveHandler, rejectHandler).catch()

更有用,因为

  1. 我可以使用rejectHandler 来解决调用Promise.reject 的设计/预期错误场景。
  2. 我可以使用 catch 块来解决发生的未知/意外编程/运行时错误。

有人知道为什么拒绝处理程序没有被大量使用的任何特殊原因吗?

附:我知道 ES6 中有更新的替代品,但我只是想知道这一点。

更新:我知道rejectHandler 和catch 是如何工作的。问题是为什么我看到更多的人只使用catch 而不是rejectHandler 和catch?这是最佳做法还是有一些优势?

更新(在此处添加答案):找到我正在寻找的第一手答案。 原因不仅仅是因为拒绝中的错误是由catch处理的,主要是因为链接。当我们链接promise.then.then.then.then 时,有一个resolve,reject 模式证明链接它有点棘手,因为您不想实现rejecthandler 只是为了将rejectData 转发到链上。仅使用 promise/then/catch 和 resolve/return/throw 在链接 N 个 thenable 时非常有用。 @Bob-Fanger(接受的答案)也解决了其中的一部分问题。 例如:

getData(id) {
        return service.getData().then(dataList => {
            const data = dataList.find(data => {
                return data.id === id;
            });
            if (!data) {
                // If I use Promise.reject here and use a reject handler in the parent then the parent might just be using the handler to route the error upwards in the chain
              //If I use Promise.reject here and parent doesn't use reject handler then it goes to catch which can be just achieved using throw.
                throw {
                    code: 404,
                    message: 'Data not present for this ID'
                };
            }
            return configuration;
        });
    }


//somewhere up the chain
....getConfiguration()
            .then(() => {
                //successful promise execution
            })
            .catch(err => {
                if (err.code) {
                    // checked exception
                    send(err);
                } else {
                    //unchecked exception
                    send({
                        code: 500,
                        message: `Internal Server error: ${err}`
                    });
                }
            });

仅使用这些我需要担心的是 promise/then/catch 以及 resolve/return/throw 在链中的任何位置。

【问题讨论】:

  • “这是最佳实践还是有一些优势?” 只需编写一个函数而不是两个?我认为没有围绕这一点建立最佳实践。我认为人们只是觉得这更容易理解。
  • “这是最佳实践还是有一些优势?” 没有任何技术优势(因此,没有最佳实践)。正如我在回答中所说,这实际上取决于您需要代码来实现什么。
  • P.S.我知道 ES6 中有更新的替代品,但我只是想知道这一点。 - 什么是更新的替代品?
  • 就我个人而言,我在实际符合要求的单一场合使用了promise.then(resolveHandler, rejectHandler).catch(catchHandler)“模式”。然后我意识到需要重新访问并不再使用该模式
  • 我很确定这里有几个重复的,因为这肯定已经被问过了。我会尽力找到他们。主要区别在于.catch() 处理程序还将捕获resolveHandler 中的任何异常或拒绝,但rejectHandler 不会。

标签: javascript node.js promise


【解决方案1】:

两者都不比另一个更有用。当抛出错误或 promise 被拒绝时,rejected handler 和 catch 回调都会被调用。

没有“最佳实践”可以使用其中一种。您可能会看到代码使用一种或另一种,但它的使用将基于代码需要实现的目标。程序员可能希望在链中的不同时间捕获错误并以不同方式处理在不同时间抛出的错误。

希望以下内容有助于解释我的意思:

somePromise
  .then(
      function() { /* code when somePromise has resolved */ },
      function() { 
        /* code when somePromise has thrown or has been rejected. 
        An error thrown in the resolvedHandler 
        will NOT be handled by this callback */ }
   );

somePromise
  .then(
      function() { /* code when somePromise has resolved */ }
   )
   .catch(
      function() { 
        /* code when somePromise has thrown or has been rejected OR 
        when whatever has occurred in the .then 
        chained to somePromise has thrown or 
        the promise returned from it has been rejected */ }
   );

请注意,在第一个 sn-p 中,如果已解决的处理程序抛出,则没有可以捕获错误的被拒绝处理程序(或 catch 回调)。在解析的回调中抛出的错误不会被指定为 .then 的第二个参数的 deniedHandler 捕获

【讨论】:

  • 谢谢。 “没有“最佳实践”来使用其中一个。你可能会看到代码使用其中一个,但它的使用将基于代码需要实现的目标。这解释了
【解决方案2】:

如帖子中所述,在对.then 的同一调用中提供解析和拒绝处理程序允许将先前承诺的拒绝与成功处理程序中抛出的错误分开处理,或从成功处理程序返回被拒绝的承诺。

因为没有抛出错误而返回的拒绝处理程序会恢复 Promise 链的已完成通道,所以如果先前的拒绝处理程序正常返回,则不会调用最终的 catch 处理程序。

然后问题转变成用例、开发成本和知识水平。

用例

理论上then调用的两个参数形式可以用来重试一个操作。但是因为硬编码的承诺链是静态设置的,所以重试操作并不简单。更简单的重试方法可能是使用 async 函数和围绕 await 可能需要重试的承诺的 try-catch 语句,如本概念代码中所示:

async function() {
    let retries = 3;
    let failureErr = null;
    while( retries--) {
       try {
          var result = await retryableOperationPromise() 
          return result;
       }
       catch( err) {
          failureErr = err;
       }
     }
     throw failureErr // no more retries
}

其他用例可能并不广泛。

开发或商业决策的成本。

如果告诉用户稍后重试是可以接受的,那么它可能比针对拒绝承诺的具体原因做任何事情要便宜。例如,如果我尝试在午夜预订航班,当航空公司提高价格时,我通常会被告知“发生错误,稍后再试”,因为我在预订开始时给出的价格将不会兑现。

知识()

我怀疑 Promise 的使用通常基于示例而不是对该主题的深入了解。对于经验不足的开发人员,项目经理也可能希望代码库尽可能简单(可能是成本问题)。

如果使用是有效的,“最佳实践”可能并不真正适用于决定如何使用承诺。一些开发人员和管理人员原则上会避免某些形式的使用,但并不总是基于技术优势。

【讨论】:

    【解决方案3】:

    不同的是,如果resolveHandler内部发生错误,rejectHandler不会处理它,它只处理原始promise中的拒绝。

    rejectHandler 并没有太多地与 catch 结合使用,因为大多数时候我们只关心某事出了什么问题。
    只创建一个错误处理程序使代码更容易推理。

    如果链中的特定承诺应该以不同方式处理,这可能是使用拒绝处理程序的原因,但在这种情况下我可能会写一个catch().then().catch()

    【讨论】:

    • 有趣的解释。同样关于您的观点,“rejectHandler 并没有与 catch 结合使用那么多,因为大多数时候我们只关心出了什么问题。”,确实我们只考虑出了什么问题,尽管我随着时间的推移意识到了这一点如果这是预期的错误或意外的,最好考虑一下
    猜你喜欢
    • 2021-04-21
    • 2016-11-10
    • 2016-09-18
    • 2016-02-19
    • 1970-01-01
    • 2015-04-26
    • 2018-08-26
    • 1970-01-01
    • 2015-10-06
    相关资源
    最近更新 更多