实现 Promise.race

手写实现 Promise.race 方法,返回最先完成的 Promise 结果

问题

Promise.race 是 Promise 的一个静态方法,它接收一个 Promise 数组作为参数,返回一个新的 Promise。这个新 Promise 会在数组中任意一个 Promise 率先完成(无论是 resolve 还是 reject)时,以相同的状态和值完成。简单来说,就是”赛跑”机制,谁先完成就返回谁的结果。

解答

/**
 * 实现 Promise.race
 * @param {Array} promises - Promise 数组
 * @returns {Promise} 返回最先完成的 Promise 结果
 */
Promise.myRace = function(promises) {
  // 返回一个新的 Promise
  return new Promise((resolve, reject) => {
    // 参数校验:必须是可迭代对象
    if (!Array.isArray(promises)) {
      return reject(new TypeError('参数必须是一个数组'));
    }
    
    // 如果传入空数组,返回的 Promise 将永远处于 pending 状态
    if (promises.length === 0) {
      return;
    }
    
    // 遍历所有 Promise
    for (let i = 0; i < promises.length; i++) {
      // 使用 Promise.resolve 包装,确保处理非 Promise 值
      Promise.resolve(promises[i])
        .then(
          value => {
            // 任意一个 Promise 成功,立即 resolve
            resolve(value);
          },
          reason => {
            // 任意一个 Promise 失败,立即 reject
            reject(reason);
          }
        );
    }
  });
};

使用示例

// 示例1:基本使用
const promise1 = new Promise((resolve) => {
  setTimeout(() => resolve('第一个完成'), 100);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => resolve('第二个完成'), 50);
});

const promise3 = new Promise((resolve) => {
  setTimeout(() => resolve('第三个完成'), 200);
});

Promise.myRace([promise1, promise2, promise3])
  .then(result => {
    console.log(result); // 输出: '第二个完成'
  });

// 示例2:包含 reject 的情况
const fastReject = new Promise((resolve, reject) => {
  setTimeout(() => reject('快速失败'), 30);
});

const slowResolve = new Promise((resolve) => {
  setTimeout(() => resolve('慢速成功'), 100);
});

Promise.myRace([fastReject, slowResolve])
  .then(result => {
    console.log('成功:', result);
  })
  .catch(error => {
    console.log('失败:', error); // 输出: '失败: 快速失败'
  });

// 示例3:包含非 Promise 值
Promise.myRace([100, Promise.resolve(200), Promise.resolve(300)])
  .then(result => {
    console.log(result); // 输出: 100(非 Promise 值会被立即 resolve)
  });

// 示例4:实际应用场景 - 请求超时控制
function requestWithTimeout(url, timeout = 5000) {
  const fetchPromise = fetch(url);
  
  const timeoutPromise = new Promise((resolve, reject) => {
    setTimeout(() => reject('请求超时'), timeout);
  });
  
  return Promise.myRace([fetchPromise, timeoutPromise]);
}

requestWithTimeout('https://api.example.com/data', 3000)
  .then(response => console.log('请求成功', response))
  .catch(error => console.log('请求失败', error));

关键点

  • 返回新 Promise:race 方法返回一个新的 Promise 实例,而不是修改原有的 Promise

  • 竞态机制:遍历所有 Promise,哪个先完成(resolve 或 reject)就采用哪个结果

  • Promise.resolve 包装:使用 Promise.resolve() 包装每个元素,确保能正确处理非 Promise 值(如普通值、thenable 对象等)

  • 状态不可逆:Promise 一旦状态改变就不可再变,所以第一个完成的 Promise 会决定最终结果,后续的 Promise 完成不会影响结果

  • 空数组处理:传入空数组时,返回的 Promise 会永远处于 pending 状态,这与原生 Promise.race 行为一致

  • 错误处理:任何一个 Promise 的 reject 都会导致 race 返回的 Promise 被 reject

  • 实际应用:常用于超时控制、多个数据源竞速获取、快速失败机制等场景