Promise.all API 调用,区分哪个抛出错误,只拒绝一个

Posted

技术标签:

【中文标题】Promise.all API 调用,区分哪个抛出错误,只拒绝一个【英文标题】:Promise.all API calls, distinguish which threw error and reject only one 【发布时间】:2020-11-07 17:55:40 【问题描述】:

所需信息:使用 NodeJS 框架,Promises.all 仅与 API 调用一起使用,因此异步代码

所以我的问题的基础在于我需要创建两个 API 调用,我们称它们为 A 和 B。保证 A 将返回数据或 404,而 B 将返回空数组、数据或404(但这里的 404 表示无效输入,而在 API 调用 A 中,它实际上表示未找到资源)。我的问题是,如果 A 确实返回 404,Promise.all 将像往常一样拒绝并跳入 catch 块。

我想要的功能是,如果 API 调用 A 返回 404,我希望 API 调用 B 继续并检索该数据,继续我的代码。有没有办法区分甚至分别捕获两个 API 调用引发的错误,如果一个解决了则继续执行??

示例代码目前如下所示:

function(param) 
  const A = apiCallA();
  const B = apiCallB();

  return Promise.all([A, B])
  .then( ([resA, resB]) => 
    // If resA is null, catch the error but continue with
    // resB. If this is null also Promise.reject('both API calls failed')

    // else if both resA && resB != null, do some stuff and resolve
  )
  .catch( (err) => 
    // Here is where my question lies. The err object can be either from API call A or B.
    // How would I distinguish this?
  );

【问题讨论】:

【参考方案1】:

有多种选择。

    您可以在 Promise.all() 之前从 API 调用 A 中捕获错误,并将其转换为成功的请求,但已适当标记,从而允许 Promise.all() 完成。

    无论成功或失败,您都可以使用Promise.allSettled() 获得这两个结果。

对于第一个选项,您可以在 apiCallA() 上放置一个 .catch() 处理程序,它将任何拒绝转换为解决,但会使用错误对象进行解决,您可以稍后检查是否需要:

function(param) 
  const A = apiCallA().catch(err =>  return err );
  const B = apiCallB();

  return Promise.all([A, B]).then( ([resA, resB]) => 
      // you can check if resA succeeded here
      if (resA instanceof Error) 
          // resA actually failed
          console.log(resA);
      
  ).catch( (err) => 
      // you would only get here if resB failed
  );

对于第二个选项,您使用Promise.allSettled()

function(param) 
  const A = apiCallA();
  const B = apiCallB();

  return Promise.allSettled([A, B]).then( ([resA, resB]) => 
    // check both resA.status and resB.status
    if (resA.status === "fulfilled") 
       console.log(resA.value);
    
    if (res === "fulfilled") 
       console.log(resB.value);
    
  );

【讨论】:

第二个选项Promise.allSettled() 听起来非常完美。你能再描述一下吗? MDN 文档 (developer.mozilla.org/en-US/docs/Web/javascript/Reference/…) 给我留下了一些问题。我会留意文字“履行”和“拒绝”吗?我还能添加一个 catch 块吗?编辑:我现在看到你已经更新了答案。我会试试这个,从编程和逻辑上看,看起来正是我需要的。 @MariosYiannakou - 我添加了Promise.allSettled()的代码示例 @MariosYiannakou - 如果这回答了您的问题,您可以通过单击答案左侧的复选标记向社区表明这一点。这也将为您在此处遵循正确的程序赢得一些声誉积分。 您的第一个解决方案效果更好,因为 Promise.allSettled 未被识别为函数。不确定我是否遗漏了一些东西。只是想让其他阅读本文的人知道。 @MariosYiannakou - 你运行的是什么版本的 nodejs?我认为Promise.allSettled() 是在节点 v12.9.0 中添加的。

以上是关于Promise.all API 调用,区分哪个抛出错误,只拒绝一个的主要内容,如果未能解决你的问题,请参考以下文章

在 node js 中使用 promise.all 进行外部 api 调用

TypeError: #<Promise> 不可迭代

为啥即使我 .catch() Promise.all() 也会抛出异常?

如何使用并区分Promise.all和Promise.race?

节点使用带有 .catch() 语句的 Promise.all 为 Mongoose 请求抛出 UnhandledPromiseRejectionWarning

如何用 Promise.all 替换多个 async/await 调用?