手写 Promise.race 也是一个很好的练习,可以帮助理解 Promise 的并发处理逻辑。Promise.race 的作用是等待传入的多个 Promise 中任意一个最先完成(resolve 或 reject),并立即返回该结果。
实现思路
- 初始化状态:创建一个新的
Promise实例。 - 监听结果:遍历传入的
promises数组,监听每个Promise的结果。 - 处理完成状态:只要有任意一个
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
});
解释
- 创建新的
Promise实例:myPromiseRace函数返回一个新的Promise实例。 - 监听结果:使用
forEach遍历promises数组,并为每个Promise添加.then()和.catch()监听器。 - 处理完成状态:只要有任意一个
Promise完成(resolve 或 reject),立即返回结果。
测试代码
上面的测试代码展示了如何使用 myPromiseRace 函数。当多个 Promise 同时运行时,输出最先完成的那个 Promise 的结果。如果有任何一个 Promise 失败,则立即返回错误信息。
总结
通过手写 Promise.race,我们可以更好地理解 Promise 的并发处理逻辑。这种方法不仅有助于学习 Promise 的基本概念,还能加深对并发编程的理解。在实际开发中,这种实现方式也能帮助我们更好地处理多个异步任务的并发执行。
扩展实现
如果你想要进一步扩展 Promise.race 的功能,可以考虑以下几点:
- 空数组处理:如果传入的
promises数组为空,应该返回一个立即 resolve 的Promise。 - 错误处理:如果传入的
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 对象的处理,使其更加健壮。