实现 Promise.any

手写 Promise.any 方法

问题

从零实现 Promise.any 方法。Promise.any 接收一组 Promise,只要有一个成功就返回该结果;全部失败则抛出 AggregateError

解答

Promise.myAny = function (promises) {
  return new Promise((resolve, reject) => {
    // 转换为数组
    const promiseArr = Array.from(promises);

    // 空数组直接拒绝
    if (promiseArr.length === 0) {
      reject(new AggregateError([], 'All promises were rejected'));
      return;
    }

    const errors = []; // 收集所有错误
    let rejectedCount = 0;

    promiseArr.forEach((promise, index) => {
      // 包装非 Promise 值
      Promise.resolve(promise).then(
        // 任意一个成功,立即 resolve
        (value) => resolve(value),
        // 失败则记录错误
        (error) => {
          errors[index] = error;
          rejectedCount++;

          // 全部失败,抛出 AggregateError
          if (rejectedCount === promiseArr.length) {
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        }
      );
    });
  });
};

测试

// 测试1:有成功的情况
const p1 = Promise.reject('error1');
const p2 = Promise.resolve('success');
const p3 = Promise.reject('error3');

Promise.myAny([p1, p2, p3]).then(console.log); // 'success'

// 测试2:全部失败
const p4 = Promise.reject('error1');
const p5 = Promise.reject('error2');

Promise.myAny([p4, p5]).catch((e) => {
  console.log(e instanceof AggregateError); // true
  console.log(e.errors); // ['error1', 'error2']
});

// 测试3:空数组
Promise.myAny([]).catch((e) => {
  console.log(e.message); // 'All promises were rejected'
});

关键点

  • 任意一个 Promise 成功就立即 resolve,不等待其他
  • 全部失败时抛出 AggregateError,包含所有错误
  • Promise.resolve() 包装输入,兼容非 Promise 值
  • 错误数组要保持原始索引顺序
  • 空数组直接拒绝,返回空的 AggregateError