【问题标题】:Cleaner way to catch an error in a chain of nested promises?在嵌套承诺链中捕获错误的更简洁方法?
【发布时间】:2017-12-13 16:14:06
【问题描述】:

我是使用 Promise 的新手,我注意到,为了在嵌套的 Promise 链中捕获错误,我需要在链中的每个 Promise 上调用 catch 方法。有没有更简洁的方法来写这个?

      poll.pollForCandidates().then((candidates) => {
        let clientId = candidates[0].clientId;
        poll.getUnprocessedCandidates({context, clientId, candidates})
          .then((unprocessedCandidates) => {
            console.log(unprocessedCandidates);
            poll.addCandidatesToQueue(context, unprocessedCandidates)
              .then((processedCandidates) => {
                console.log(processedCandidates);
                poll.addCandidatesToTable(processedCandidates)
                  .then((result) => {
                    console.log(result);
                  })
                  .catch((error) => {
                    console.log(error);
                  });
              })
              .catch((error) => {
                console.log(error); 
              })
          })
          .catch((error) => {
             console.log(error); 
          })
      })
      .catch(() => {
        console.done(error); 
      });
    };

【问题讨论】:

  • 哦不!我记得这是一个很常见的反模式。从.then 返回承诺。并且下一个 .then 处理程序将具有返回的承诺的已解决/拒绝值
  • 我认为“异步”库会是更好的方法。你试过异步瀑布吗?
  • 使用await。但是使用您现有的代码,您还可以删除除最后一个之外的所有 .catch(error => console.done(error) 调用。他们什么都不做。
  • 几乎所有这些.catch() 陈述都是错误的,原因有几个。您应该链接您的语句,并且只在您实际需要处理错误的地方放置一个.catch()。另外,这些.catch() 语句只记录并且不返回任何内容实际上将承诺从拒绝更改为履行,这可能不是您想要的。

标签: javascript ecmascript-6 promise


【解决方案1】:

这是更短的方法:

poll.pollForCandidates()
    .then((candidates) => poll.getUnprocessedCandidates({ context, candidates[0].clientId, candidates }))
    .then((unprocessedCandidates) => poll.addCandidatesToQueue(context, unprocessedCandidates))
    .then((processedCandidates) => poll.addCandidatesToTable(processedCandidates))
    .then(console.log)
    .catch(console.error);

解释:

这叫做组合promise,它是promise的超级大国之一。每个函数只会在前一个 Promise 完成后调用,并且会使用该 Promise 的输出调用。

你可以在 then 函数中做三件事:

  1. 返回另一个承诺
  2. 返回一个同步值(或未定义)
  3. 引发同步错误

在上面的示例中,我们返回一个承诺,因此我们可以使用.then 继续组合承诺

最后,console.log 得到结果并用它调用console.log。 (与console.error 相同)

就是这样。一旦你理解了这个技巧,你就理解了 Promise。

您可以在此处继续阅读: We have a problem with promises - By: Nolan Lawson

【讨论】:

    【解决方案2】:

    就像提到的@bugwheels94 一样,您可以从.then 中返回您的承诺,并在之前的.then 之外添加另一个.then。此外,.then 可以接受 2 个参数 - 第二个用于捕获错误。用语言解释有点困难,所以这里举个例子。

    poll.pollForCandidates()
      .then((candidates) => {
        let clientId = candidates[0].clientId;
    
        return poll.getUnprocessedCandidates({context, clientId, candidates})
          .then((unprocessedCandidates) => {
            console.log(unprocessedCandidates);
            return poll.addCandidatesToQueue(context, unprocessedCandidates)
          }, (error) => {
             console.log(error); 
          })
          .then((processedCandidates) => {
            console.log(processedCandidates);
            return poll.addCandidatesToTable(processedCandidates)
          }, (error) => {
            console.log(error); 
          })
          .then((result) => {
            console.log(result);
          }), (error) => {
            console.log(error);
          });
      })
      .catch((error) => {
        console.log(error);
      });
    

    编辑:@jfriend00 提出了使用所有这些.catch 方法的好处。以下是在链末尾带有单个 .catch 的代码。

    poll.pollForCandidates()
      .then((candidates) => {
        let clientId = candidates[0].clientId;
    
        return poll.getUnprocessedCandidates({context, clientId, candidates})
          .then((unprocessedCandidates) => {
            console.log(unprocessedCandidates);
            return poll.addCandidatesToQueue(context, unprocessedCandidates)
          })
          .then((processedCandidates) => {
            console.log(processedCandidates);
            return poll.addCandidatesToTable(processedCandidates)
          })
          .then((result) => {
            console.log(result);
          });
      })
      .catch((error) => {
        console.log(error);
      });
    

    编辑 2:删除那些多余的 console.log 语句可以让它更简洁。

    poll.pollForCandidates()
      .then((candidates) => {
        let clientId = candidates[0].clientId;
    
        return poll.getUnprocessedCandidates({context, clientId, candidates})
          .then(unprocessedCandidates => poll.addCandidatesToQueue(context, unprocessedCandidates))
          .then(poll.addCandidatesToTable)
          .then((result) => {
            console.log(result);
          });
      })
      .catch((error) => {
        console.log(error);
      });
    

    【讨论】:

    • 所有这些.catch() 语句都会导致问题。有关详细信息,请参阅我对 OP 问题的评论。通常应该能够使用更少的.catch() 语句进行编码,因为错误会在承诺链中自动传播。
    • 好点。我只是试图提供与原始代码相同的功能。我会进行编辑。
    • 那么,绑定到最外层的thencatch 将捕获可能由任何链接的thens 产生的错误?
    • @MichaelP。 - 只要您从.then() 处理程序中返回嵌套的promise,允许它们链接到前一个链,链中任何地方的拒绝都会一直传播到顶层并传播到最后的.catch()。这就是 Promise 真正发挥作用的地方(复杂的多步异步流程中的错误处理)。
    猜你喜欢
    • 2018-10-16
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多