实现 Promise.all 方法
不使用 Promise.all 实现并发执行多个 Promise
问题
实现一个 myAll 方法,功能与 Promise.all 相同,但不能直接使用 Promise.all 语法。
解答
错误实现(串行执行)
async function myAll<T extends unknown[] | []>(
values: T
): Promise<{ [P in keyof T]: Awaited<T[P]> }> {
const arr = [];
for (let i = 0; i < values.length; i++) {
arr.push(await values[i]);
}
return arr as { [P in keyof T]: Awaited<T[P]> };
}
这个实现有问题:使用 await 在循环中会导致串行执行,失去了并发的优势。
正确实现(并发执行)
async function myAll<T extends unknown[] | []>(
values: T
): Promise<{ [P in keyof T]: Awaited<T[P]> }> {
return new Promise((resolve, reject) => {
const results: any[] = [];
let completed = 0;
if (values.length === 0) {
resolve(results as { [P in keyof T]: Awaited<T[P]> });
return;
}
values.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
results[index] = value;
completed++;
if (completed === values.length) {
resolve(results as { [P in keyof T]: Awaited<T[P]> });
}
})
.catch(reject);
});
});
}
使用示例
async function request(value: string) {
await sleep(1000);
return value;
}
// 三个请求并发执行,总耗时约 1 秒
const results = await myAll([
request('a'),
request('b'),
request('c')
]);
关键点
- 循环中使用
await会导致串行执行,每个 Promise 依次等待 - 正确做法是先启动所有 Promise,再统一等待结果
- 使用计数器追踪完成数量,所有 Promise 完成后才 resolve
- 用
Promise.resolve()包装值,确保非 Promise 值也能正常处理 - 任何一个 Promise reject 时,整个
myAll立即 reject
目录