请说说你对Promise.any()的了解

7 阅读2分钟
Promise.any() 是 ES2021 引入的一个新的 Promise 组合器方法,它接收一个 Promise 可迭代对象(如数组),并返回一个新的 Promise。这个新 Promise 会在输入的任意一个 Promise 成功(fulfilled)时立即成功,或者在所有 Promise 都失败(rejected)时失败。

### 基本用法
```javascript
const promise1 = Promise.reject("Error 1");
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "Success"));
const promise3 = Promise.reject("Error 3");

Promise.any([promise1, promise2, promise3])
  .then((value) => {
    console.log(value); // 输出: "Success"(第一个成功的 Promise)
  })
  .catch((error) => {
    console.log(error); // 只有当所有 Promise 都失败时才会执行
  });

与 Promise.race() 的区别

  1. 行为差异

    • Promise.race():第一个 settled(无论成功或失败)的 Promise 决定结果
    • Promise.any():等待第一个成功的 Promise,只有全部失败才拒绝
  2. 错误处理

// race() 示例
Promise.race([Promise.reject("Error"), Promise.resolve("Success")])
  .catch(err => console.log(err)); // 输出: "Error"

// any() 示例
Promise.any([Promise.reject("Error"), Promise.resolve("Success")])
  .then(res => console.log(res)); // 输出: "Success"

聚合错误(AggregateError)

当所有 Promise 都失败时,会抛出一个 AggregateError:

Promise.any([Promise.reject("Error 1"), Promise.reject("Error 2")])
  .catch((error) => {
    console.log(error instanceof AggregateError); // true
    console.log(error.errors); // ["Error 1", "Error 2"]
  });

实际应用场景

  1. 多源数据获取
async function fetchFromMultipleSources(urls) {
  const promises = urls.map(url => 
    fetch(url).then(r => r.json()).catch(() => {})
  );
  return Promise.any(promises);
}
  1. 服务降级
function getData() {
  const primary = fetch('/primary-api');
  const fallback = fetch('/fallback-api');
  
  return Promise.any([primary, fallback])
    .then(data => data.json());
}

注意事项

  1. 空数组处理:传入空数组会立即拒绝
  2. 非 Promise 值:会自动用 Promise.resolve() 包装
  3. 浏览器兼容性:需要现代浏览器或 polyfill

Polyfill 实现

if (!Promise.any) {
  Promise.any = function(promises) {
    return new Promise((resolve, reject) => {
      let rejections = [];
      let pending = promises.length;
      
      if (pending === 0) {
        reject(new AggregateError([], "All promises were rejected"));
      }
      
      promises.forEach((promise, index) => {
        Promise.resolve(promise)
          .then(resolve)
          .catch(error => {
            rejections[index] = error;
            if (--pending === 0) {
              reject(new AggregateError(rejections, "All promises were rejected"));
            }
          });
      });
    });
  };
}

性能考虑

  1. 相比 Promise.all() 不会短路,会等待所有 Promise 完成
  2. 内存占用较高,因为需要跟踪所有 rejection
  3. 适合对成功结果优先级高于错误处理的场景

Promise.any() 为 Promise 组合模式提供了更完整的解决方案,特别适合需要"快速成功"的业务场景,完善了 JavaScript 的异步控制流能力。