实现 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
-
实际应用:常用于超时控制、多个数据源竞速获取、快速失败机制等场景
目录