从 Promise.all 到 Promise.allSettled:一次接口优化的真实经历

更新日期: 2025-10-15阅读: 17标签: Promise

有一次,我需要同时调用多个接口来获取数据。为了提高效率,我使用了 Promise.all 方法。代码部署后,一切看起来都很完美,我觉得自己解决了一个大问题。

但很快,问题出现了。当其中一个接口偶尔失败时,整个页面都会崩溃。用户看到的是一个错误提示,而不是他们需要的数据。这让我意识到,我需要找到一个更好的解决方案。


发现问题

在我的项目中,有一个数据面板需要从多个服务获取信息:

const [user, orders, notifications] = await Promise.all([
  getUser(),
  getOrders(),
  getNotifications(),
]);

在大多数情况下,这段代码运行得很好。但是,只要其中任何一个请求失败,整个 Promise.all 就会立即停止,并抛出错误。这意味着即使其他请求都成功了,用户也看不到任何数据。


找到解决方案

经过研究,我发现了 Promise.allSettled 这个方法。它与 Promise.all 的不同之处在于,它会等待所有请求都完成,不管它们是成功还是失败。

const results = await Promise.allSettled([
  getUser(),
  getOrders(),
  getNotifications(),
]);

// 处理结果
results.forEach(result => {
  if (result.status === 'fulfilled') {
    // 请求成功
    console.log('成功获取数据:', result.value);
  } else {
    // 请求失败
    console.log('获取数据失败:', result.reason);
  }
});


这种方法的好处

使用 Promise.allSettled 后,我获得了几个重要的优势:

  1. 显示部分数据:即使某些请求失败,成功的数据仍然可以显示给用户

  2. 明确错误位置:可以清楚地知道是哪个模块出了问题

  3. 针对性重试:只重新请求失败的接口,而不是全部重试


实际应用建议

在实际项目中,你可以这样处理:

async function loadDashboardData() {
  const results = await Promise.allSettled([
    getUserInfo(),
    getOrderList(),
    getNotificationCount(),
    getRecommendations()
  ]);
  
  const data = {};
  const errors = [];
  
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      // 根据索引确定是哪个请求的数据
      switch(index) {
        case 0: data.user = result.value; break;
        case 1: data.orders = result.value; break;
        case 2: data.notifications = result.value; break;
        case 3: data.recommendations = result.value; break;
      }
    } else {
      errors.push({index, error: result.reason});
    }
  });
  
  return {data, errors};
}


选择性重试的实现

对于失败的请求,你可以选择性地重试:

async function loadDataWithRetry() {
  let results = await Promise.allSettled(requests);
  
  // 找出失败的请求
  const failedRequests = results
    .map((result, index) => ({result, index}))
    .filter(item => item.result.status === 'rejected')
    .map(item => requests[item.index]);
  
  // 只重试失败的请求
  if (failedRequests.length > 0) {
    const retryResults = await Promise.allSettled(failedRequests);
    // 合并重试结果...
  }
  
  return results;
}


什么时候用哪个方法

根据我的经验,这两种方法各有适用场景:

使用 Promise.all 的情况:

  • 用户登录验证(所有步骤都必须成功)

  • 订单支付流程(每个环节都不能出错)

  • 数据提交(所有操作都要完成)

使用 Promise.allSettled 的情况:

  • 数据面板显示(部分数据可用就好)

  • 侧边栏小工具(某些内容可以缺失)

  • 推荐内容加载(没有推荐也能正常使用)


最佳实践

  1. 区分重要程度:把关键数据和次要数据分开处理

  2. 提供备用方案:对于失败的内容,显示占位符或默认内容

  3. 用户提示:告诉用户哪些内容暂时不可用

  4. 错误记录:记录失败的原因,便于后续优化


代码示例:混合使用

async function loadPageData() {
  // 关键数据 - 必须成功
  const [user, mainContent] = await Promise.all([
    getUserData(),
    getMainContent()
  ]);
  
  // 次要数据 - 可有可无
  const secondaryResults = await Promise.allSettled([
    getRecommendations(),
    getSidebarWidgets(),
    getAdvertisement()
  ]);
  
  return {
    user,
    mainContent,
    secondaryData: processSecondaryResults(secondaryResults)
  };
}


总结

从 Promise.all 切换到 Promise.allSettled,虽然只是一个小小的改变,但却显著提升了应用的稳定性。用户不再因为某个非关键接口的失败而看到空白页面,而是能够继续使用其他正常的功能。

在实际开发中,理解不同工具的特点,并在合适的场景使用它们,这是提升代码质量的重要一步。如果你的项目中也存在类似的情况,不妨试试 Promise.allSettled,它可能会帮你避免很多意想不到的问题。

记住,好的代码不仅要考虑正常情况,还要为可能出现的异常情况做好准备。这样才能打造出真正稳定可靠的应用。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/13010

你真的了解 Promise 吗?Promise 必知必会(十道题)

Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。

剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.

Async/Await替代Promise的6个理由

Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。

Promise 原理解析与实现(遵循Promise/A+规范)

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数

简单模仿实现 Promise 的异步模式

这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。

数组的遍历你都会用了,那Promise版本的呢

在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,

Promise使用时应注意的问题

最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因

es6 Promise 的基础用法

想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行

关于 Promise 的 9 个提示

你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve

手写一款符合Promise/A+规范的Promise

Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难.本篇大概分为以下步骤:实现简单的同步Promise、增加异步功能、增加链式调用then、增加catch finally方法、增加all race 等方法、实现一个promise的延迟对象defer、最终测试

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!