除了Promise.all,还有哪些方法可以处理多个异步操作?

简介: 除了Promise.all,还有哪些方法可以处理多个异步操作?

除了 Promise.all(),JavaScript 还提供了多个专门处理多个异步操作的 Promise 静态方法,适用于不同的业务场景(如“只要一个完成”“等待所有完成但保留失败信息”“按顺序执行”等)。以下是核心方法的详细说明:

一、Promise.race():“竞速模式”,取第一个完成的结果

Promise.race() 接收一个 Promise 可迭代对象(如数组),哪个异步操作先完成(无论成功或失败),就立即返回该操作的结果(成功值或失败原因),忽略其他未完成的操作。

核心场景:

  • 异步操作的超时控制(如“接口请求 5 秒内没响应则提示超时”);
  • 优先使用“最快可用的资源”(如同时请求多个 CDN,取第一个返回的资源)。

示例:实现接口请求超时控制

// 1. 模拟真实接口请求(假设可能耗时较久)
const fetchData = new Promise((resolve) => {
   
  setTimeout(() => resolve("接口请求成功,返回数据"), 3000); // 3秒后成功
});

// 2. 模拟超时定时器(5秒后触发超时)
const timeout = new Promise((_, reject) => {
   
  setTimeout(() => reject(new Error("请求超时,请重试")), 5000); // 5秒后失败
});

// 3. 竞速:谁先完成就用谁的结果
Promise.race([fetchData, timeout])
  .then((data) => {
   
    console.log("成功:", data); // 3秒后执行,输出:接口请求成功...
  })
  .catch((error) => {
   
    console.error("失败:", error.message); // 若接口超过5秒,输出:请求超时...
  });

注意:

  • 一旦有一个操作完成,Promise.race() 会立即确定结果,其他未完成的操作会被“静默忽略”(但不会终止其内部执行,只是不再处理其结果)。

二、Promise.allSettled():“全量模式”,保留所有操作的结果

Promise.allSettled() 接收一个 Promise 可迭代对象,等待所有异步操作全部完成(无论成功或失败),最终返回一个包含所有操作结果的数组。每个结果对象包含两个属性:

  • status:操作状态,值为 fulfilled(成功)或 rejected(失败);
  • value(仅成功时):异步操作的成功结果;
  • reason(仅失败时):异步操作的失败原因。

核心场景:

  • 需要完整知道所有异步操作的结果(成功/失败都要处理),而非“有一个失败就终止”;
  • 批量任务的“结果汇总”(如批量上传文件,需要知道每个文件的上传状态)。

示例:批量处理异步操作并汇总结果

// 模拟3个异步操作(2个成功,1个失败)
const task1 = Promise.resolve("任务1成功");
const task2 = Promise.reject(new Error("任务2失败:网络错误"));
const task3 = new Promise((resolve) => setTimeout(() => resolve("任务3成功"), 1000));

// 等待所有任务完成,汇总结果
Promise.allSettled([task1, task2, task3])
  .then((results) => {
   
    // 遍历结果数组,分别处理成功和失败
    results.forEach((result, index) => {
   
      if (result.status === "fulfilled") {
   
        console.log(`任务${
     index + 1}成功:`, result.value);
      } else {
   
        console.error(`任务${
     index + 1}失败:`, result.reason.message);
      }
    });
  });

// 输出结果:
// 任务1成功:任务1成功
// 任务2失败:网络错误
// 任务3成功:任务3成功

与 Promise.all() 的区别:

特性 Promise.all() Promise.allSettled()
结果触发条件 所有成功 或 第一个失败 所有操作全部完成(无论成败)
结果形式 成功值数组 或 单个失败原因 包含所有操作状态的结果对象数组
错误处理 快速失败(一个失败则整体失败) 不“失败”,仅在结果中标记失败

三、Promise.any():“择优模式”,取第一个成功的结果

Promise.any() 接收一个 Promise 可迭代对象,等待第一个“成功”的异步操作,并返回其成功结果;只有当所有操作都失败时,才返回一个包含所有失败原因的 AggregateError(聚合错误)。

核心场景:

  • 优先使用“第一个成功的资源”(如同时请求多个接口,只要有一个返回有效数据就用);
  • 避免因单个操作失败导致整体不可用(容错性比 Promise.race() 更高)。

示例:优先获取第一个成功的接口数据

// 模拟3个接口请求(2个失败,1个成功)
const api1 = new Promise((_, reject) => setTimeout(() => reject(new Error("接口1超时")), 1000));
const api2 = new Promise((resolve) => setTimeout(() => resolve("接口2返回:用户数据"), 1500));
const api3 = new Promise((_, reject) => setTimeout(() => reject(new Error("接口3报错")), 2000));

// 取第一个成功的结果
Promise.any([api1, api2, api3])
  .then((data) => {
   
    console.log("成功获取数据:", data); // 1.5秒后执行,输出:接口2返回:用户数据
  })
  .catch((errors) => {
   
    // 只有所有操作都失败时才执行
    console.error("所有接口都失败:", errors.errors); // 包含所有失败原因的数组
  });

与 Promise.race() 的区别:

特性 Promise.race() Promise.any()
结果触发条件 第一个完成(无论成功或失败) 第一个成功(忽略失败,直到全部失败)
失败条件 第一个操作失败则整体失败 所有操作都失败才整体失败
适用场景 超时控制(关注“是否超时”) 资源择优(关注“是否有成功”)

四、串行处理多个异步操作(非静态方法,基于 then 链式调用)

上述方法均为并行处理异步操作(同时执行多个),但如果需要按顺序执行多个异步操作(前一个完成后再执行下一个),则需通过 Promise.then() 链式调用或 async/await 实现(本质仍是基于 Promise)。

示例:按顺序请求接口(依赖前一个接口的结果)

// 模拟按顺序请求:先获取用户ID,再用ID获取用户详情
const fetchUserId = () => Promise.resolve("user_123"); // 第一步:获取ID
const fetchUserDetail = (userId) => Promise.resolve({
    id: userId, name: "Alice" }); // 第二步:用ID获取详情

// 链式调用实现串行
fetchUserId()
  .then((userId) => {
   
    console.log("第一步:获取到用户ID", userId);
    return fetchUserDetail(userId); // 传递ID给下一个异步操作
  })
  .then((userDetail) => {
   
    console.log("第二步:获取到用户详情", userDetail); // 输出:{ id: "user_123", name: "Alice" }
  });

// 或用 async/await 简化(更直观)
const getuserInfo = async () => {
   
  const userId = await fetchUserId();
  const userDetail = await fetchUserDetail(userId);
  console.log("用户详情:", userDetail);
};
getuserInfo();

总结:方法选择指南

根据业务场景选择合适的方法:

场景需求 推荐方法
所有操作成功才继续,一个失败则整体失败 Promise.all()
只要有一个操作完成(无论成败)就继续 Promise.race()
所有操作都完成,需要知道每个的成功/失败 Promise.allSettled()
只要有一个操作成功就继续,所有失败才报错 Promise.any()
多个操作需按顺序执行(依赖前一个结果) then 链式调用 / async/await
目录
相关文章
|
1月前
|
存储 Linux
Linux 目录名称
Linux系统目录结构简介:根目录(/)下包含各类功能目录,如/bin存放用户命令,/etc存储配置文件,/home为用户主目录,/var记录日志等可变数据,/usr存放用户工具,/tmp用于临时文件。各目录分工明确,保障系统有序运行。(238字)
186 5
|
JavaScript 前端开发 搜索推荐
不想要网页默认的右键菜单栏,怎么封装一个可以自定义的右键菜单组件?
不想要网页默认的右键菜单栏,怎么封装一个可以自定义的右键菜单组件?
303 0
|
2月前
|
监控 安全 Java
Spring Cloud 微服务治理技术详解与实践指南
本文档全面介绍 Spring Cloud 微服务治理框架的核心组件、架构设计和实践应用。作为 Spring 生态系统中构建分布式系统的标准工具箱,Spring Cloud 提供了一套完整的微服务解决方案,涵盖服务发现、配置管理、负载均衡、熔断器等关键功能。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
191 1
|
前端开发 开发者
类组件(Class component)和 函数式组件(Functional component) 之间有何区别?
类组件(Class component)和 函数式组件(Functional component) 之间有何区别?
281 0
|
11月前
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
存储 区块链 数据安全/隐私保护
Uniswap丨justswap丨pancakeswap去中心化薄饼交易所系统开发逻辑分析及源码示例
Uniswap、JustSwap、PancakeSwap均为去中心化交易所,采用自动做市商(AMM)机制。Uniswap基于以太坊,通过Router、Factory和Pair合约实现交易功能;JustSwap基于TRON网络,支持TRC20代币交易,无手续费;PancakeSwap基于Binance Smart Chain,功能类似Uniswap,支持BSC代币交易。
|
JavaScript 前端开发 图形学
WebGL 技术详解
【10月更文挑战第7天】
648 132
|
资源调度
安装项目的时候老是报错:Command failed.
安装项目的时候老是报错:Command failed.
371 122
|
Web App开发 存储 前端开发
Chrome浏览器的跨域问题
Chrome浏览器的跨域问题
859 128
|
存储 缓存 前端开发
Web应用中的存储方式有哪些?
本文首发于微信公众号“前端徐徐”,介绍了几种常见的前端数据存储技术:Cookie、Web Storage(包括 localStorage 和 sessionStorage)、IndexedDB、Cache Storage 和 Memory Storage。每种技术的特点和使用场景不同,适用于不同的开发需求。文章详细解释了它们的使用方法、特点和应用场景,并提供了代码示例。
1585 2
Web应用中的存储方式有哪些?