基于 ECMA-262 规范模拟实现的 Promise.any 函数

本文介绍了如何在JavaScript中扩展Promise原型,实现`Promise.any`方法,以便处理异步数组中的第一个解决或拒绝的Promise。方法通过遍历Promise数组,确保每个Promise都转换为Promise对象,然后根据结果决定整体Promise的状态。
摘要由CSDN通过智能技术生成
// 假设这是内置 Promise 的扩展部分
// 若原生 Promise 不包含 .any 方法,则将其添加
if (typeof Promise.prototype.any !== 'function') {
  // 定义 Promise.any 方法
  Promise.any = function(promises) {
    // 检查输入是否为数组,如果不是但具有可迭代性,则转化为数组
    if (!Array.isArray(promises)) {
      if (promises[Symbol.iterator]) {
        promises = [...promises];
      } else {
        throw new TypeError('Promise.any expects an array or iterable object');
      }
    }

    // 创建一个新的 Promise 对象,用于封装最终的解决或拒绝结果
    return new Promise((resolve, reject) => {
      // 存储成功结果的数组(此处不需要,但为了完整性保留)
      const results = [];
      // 存储每个被拒绝 Promise 的错误信息
      let errors = [];
      // 记录有多少个 Promise 已经进入 fulfilled 或 rejected 状态
      let settledCount = 0;

      // 处理单个 Promise 解决或拒绝的方法
      const resolveOrRejectOne = (value, isError) => {
        // 当第一个 Promise 被解决时,解决外部包装的 Promise
        if (settledCount === 0) {
          if (!isError) {
            resolve(value);
          } else {
            // 如果所有 Promise 都被拒绝,创建一个 AggregateError 并拒绝外部包装的 Promise
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        }
        // 增加已解决或拒绝的 Promise 计数
        settledCount++;
      };

      // 遍历传入的 Promise 数组
      promises.forEach((p, index) => {
        // 使用 Promise.resolve 包装 Promise,确保获得 Promise 对象(即使输入已经是 Promise)
        Promise.resolve(p).then(
          // 成功回调
          value => {
            // 存储成功结果(实际上 Promise.any 只关心第一个解决的,所以这里存储结果并不是必须的)
            results[index] = value;
            // 调用解决或拒绝方法,标记为成功
            resolveOrRejectOne(value, false);
          },
          // 失败回调
          error => {
            // 当 Promise 被拒绝时,记录下错误信息
            errors.push({ index, reason: error });
            // 标记为一个失败的 Promise
            resolveOrRejectOne(undefined, true);
          }
        );
      });
    });
  };
}

// 如果环境不支持内置的 AggregateError 类型,自定义一个
if (typeof AggregateError !== 'function') {
  class AggregateError extends Error {
    constructor(errors, message) {
      super(message);
      this.name = 'AggregateError';
      this.errors = errors;
    }
  }
}
  • 验证输入是否为可迭代对象,并转换为数组。
  • 创建一个新的 Promise,其内部维护一个已解决(resolved/rejected)Promise 的计数器和错误列> 表。
  • 遍历传入的 Promise 数组,对每个 Promise 使用 Promise.resolve 包装以确保得到一个 Promise 对象。
  • 对每个包装后的 Promise 添加 then 回调,成功时更新结果和尝试解决新创建的 Promise,失败时将错误信息存储到错误列表并在所有 Promise 都被拒绝后拒绝新创建的 Promise。
  • 如果有任何一个 Promise 成功,就直接解决新创建的 Promise 并返回其结果;如果所有 Promise 都失败,则使用 AggregateError(如果没有内置该类,则自定义一个)将所有错误合并后拒绝新创建的 Promise
  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开机就来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值