返回

剖析 Promise-Polyfill 的源代码:从 catch 到 race 的深入探索

前端

第一幕:catch - 抓住拒绝的奥秘

回想一下 catch 方法的使用场景,通常我们将其置于 Promise 链的最后,犹如一道坚固的防线,时刻准备着捕捉拒绝的原因。因此,catch 方法被定义在 Promise 的原型链上,让我们看看它的源代码:

Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
};

catch 方法其实是一个简化的 then 方法,在内部它调用 then 方法,第一个参数为 undefined,表示不关心成功的值,而第二个参数就是我们传入的 onRejected 函数,用于处理拒绝的原因。

第二幕:all - 等待所有 Promise 的绽放

all 方法是 Promise 的静态方法,它可以接收一个包含 Promise 实例的数组作为参数,然后返回一个新的 Promise。这个新的 Promise 会在所有传入的 Promise 都完成后才被决议,决议的值是一个包含所有传入 Promise 的结果的数组。

Promise.all = function (iterable) {
  return new Promise((resolve, reject) => {
    // 初始化结果数组
    const values = [];
    // 计数器,追踪已完成的 Promise 个数
    let count = 0;
    // 遍历 Promise 数组
    for (let i = 0; i < iterable.length; i++) {
      // 使用 then 方法处理每个 Promise
      Promise.resolve(iterable[i]).then(
        (value) => {
          // 将结果存储到结果数组中
          values[i] = value;
          // 计数器加一
          count++;
          // 如果所有 Promise 都已完成,则决议新的 Promise
          if (count === iterable.length) {
            resolve(values);
          }
        },
        (reason) => {
          // 如果其中一个 Promise 被拒绝,则立即拒绝新的 Promise
          reject(reason);
        }
      );
    }
  });
};

第三幕:race - 并行任务的赛跑

race 方法也是 Promise 的静态方法,它可以接收一个包含 Promise 实例的数组作为参数,然后返回一个新的 Promise。这个新的 Promise 会在数组中第一个决议或拒绝的 Promise 后立即决议或拒绝。

Promise.race = function (iterable) {
  return new Promise((resolve, reject) => {
    // 遍历 Promise 数组
    for (let i = 0; i < iterable.length; i++) {
      // 使用 then 方法处理每个 Promise
      Promise.resolve(iterable[i]).then(
        (value) => {
          // 如果其中一个 Promise 决议,则立即决议新的 Promise
          resolve(value);
        },
        (reason) => {
          // 如果其中一个 Promise 被拒绝,则立即拒绝新的 Promise
          reject(reason);
        }
      );
    }
  });
};

结语

通过对 Promise-Polyfill 源代码的深入解析,我们揭开了 catch、all 和 race 方法的神秘面纱。它们是 Promise 生态圈中不可或缺的工具,为我们提供了捕获拒绝、汇总结果和并行执行任务的能力。