手写 Promise.race

229 阅读3分钟

手写 Promise.race 也是一个很好的练习,可以帮助理解 Promise 的并发处理逻辑。Promise.race 的作用是等待传入的多个 Promise 中任意一个最先完成(resolve 或 reject),并立即返回该结果。

实现思路

  1. 初始化状态:创建一个新的 Promise 实例。
  2. 监听结果:遍历传入的 promises 数组,监听每个 Promise 的结果。
  3. 处理完成状态:只要有任意一个 Promise 完成(resolve 或 reject),立即返回结果。

代码实现

下面是一个完整的 Promise.race 的手写实现:

function myPromiseRace(promises) {
  return new Promise((resolve, reject) => {
    // 遍历 promises 数组
    promises.forEach((promise) => {
      promise.then(
        (result) => {
          resolve(result); // 只要有任意一个 Promise 成功,立即返回结果
        },
        (error) => {
          reject(error); // 只要有任意一个 Promise 失败,立即返回错误
        }
      );
    });
  });
}

// 测试代码
const promise1 = new Promise((resolve) => {
  setTimeout(() => resolve(1), 1000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => resolve(2), 500);
});

const promise3 = new Promise((resolve) => {
  setTimeout(() => resolve(3), 200);
});

myPromiseRace([promise1, promise2, promise3])
  .then((result) => {
    console.log('First resolved:', result); // 输出: First resolved: 3
  })
  .catch((error) => {
    console.error('Error:', error);
  });

const promise4 = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('Failed')), 100);
});

myPromiseRace([promise1, promise2, promise4])
  .then((result) => {
    console.log('First resolved:', result);
  })
  .catch((error) => {
    console.error('Error:', error); // 输出: Error: Failed
  });

解释

  1. 创建新的 Promise 实例myPromiseRace 函数返回一个新的 Promise 实例。
  2. 监听结果:使用 forEach 遍历 promises 数组,并为每个 Promise 添加 .then() 和 .catch() 监听器。
  3. 处理完成状态:只要有任意一个 Promise 完成(resolve 或 reject),立即返回结果。

测试代码

上面的测试代码展示了如何使用 myPromiseRace 函数。当多个 Promise 同时运行时,输出最先完成的那个 Promise 的结果。如果有任何一个 Promise 失败,则立即返回错误信息。

总结

通过手写 Promise.race,我们可以更好地理解 Promise 的并发处理逻辑。这种方法不仅有助于学习 Promise 的基本概念,还能加深对并发编程的理解。在实际开发中,这种实现方式也能帮助我们更好地处理多个异步任务的并发执行。

扩展实现

如果你想要进一步扩展 Promise.race 的功能,可以考虑以下几点:

  1. 空数组处理:如果传入的 promises 数组为空,应该返回一个立即 resolve 的 Promise
  2. 错误处理:如果传入的 promises 数组中有非 Promise 对象,应该抛出错误。

下面是扩展后的实现:

function myPromiseRace(promises) {
  if (!Array.isArray(promises)) {
    throw new TypeError('Expected an array of Promises');
  }

  if (promises.length === 0) {
    return Promise.resolve();
  }

  return new Promise((resolve, reject) => {
    // 遍历 promises 数组
    promises.forEach((promise) => {
      if (!(promise instanceof Promise)) {
        throw new TypeError('Expected a Promise, but got ' + typeof promise);
      }

      promise.then(
        (result) => {
          resolve(result); // 只要有任意一个 Promise 成功,立即返回结果
        },
        (error) => {
          reject(error); // 只要有任意一个 Promise 失败,立即返回错误
        }
      );
    });
  });
}

// 测试代码
const promise1 = new Promise((resolve) => {
  setTimeout(() => resolve(1), 1000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => resolve(2), 500);
});

const promise3 = new Promise((resolve) => {
  setTimeout(() => resolve(3), 200);
});

myPromiseRace([promise1, promise2, promise3])
  .then((result) => {
    console.log('First resolved:', result); // 输出: First resolved: 3
  })
  .catch((error) => {
    console.error('Error:', error);
  });

const promise4 = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('Failed')), 100);
});

myPromiseRace([promise1, promise2, promise4])
  .then((result) => {
    console.log('First resolved:', result);
  })
  .catch((error) => {
    console.error('Error:', error); // 输出: Error: Failed
  });

// 空数组测试
myPromiseRace([])
  .then(() => {
    console.log('Empty array resolved');
  })
  .catch((error) => {
    console.error('Error:', error);
  });

// 非 Promise 对象测试
try {
  myPromiseRace([1, 2, 3]);
} catch (error) {
  console.error('Error:', error); // 输出: Error: Expected a Promise, but got number
}

这样,myPromiseRace 函数不仅处理了并发执行的问题,还增加了对空数组和非 Promise 对象的处理,使其更加健壮。