需求背景
在开发中,我们经常遇到需要同时处理多个异步任务的情况,比如:
- 同时请求多个用户的 GitHub 仓库信息
- 多个 API 并行调用
- 批量数据处理
本文将通过一个实际案例,展示如何使用 Promise.all 优化多个异步任务的执行效率。
初始代码分析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GitHub 仓库查询</title>
</head>
<body>
<script>
// 模拟获取 GitHub 仓库信息的异步函数
const getRepos = function(id) {
return new Promise((resolve, reject) => {
try {
setTimeout(() => {
resolve({id, data: `${id}的仓库数据`})
}, 2000)
} catch(err) {
reject(err)
}
})
}
// 批量异步任务 - 原始实现
;(async() => {
const res = []
res[0] = await getRepos('LeeAt67');
res[1] = await getRepos('shunwuyu');
console.log(res);
})()
</script>
</body>
</html>
上述代码虽然能完成任务,但存在明显问题:
- 顺序执行:第二个请求必须等待第一个完成才开始
- 效率低下:总耗时 = 所有请求耗时的总和(约 4 秒)
- 代码冗余:重复的 await 语句
Promise.all 的威力
什么是 Promise.all?
Promise.all 是 JavaScript 提供的静态方法,用于处理多个 Promise 对象:
- 所有 Promise 都成功时返回结果数组
- 任何 Promise 失败则立即拒绝
- 结果顺序与输入顺序一致
- 并行执行所有异步任务
优化后的实现
;(async() => {
try {
// 使用 Promise.all 并行执行所有异步任务
const res = await Promise.all([
getRepos('LeeAt67'),
getRepos('shunwuyu'),
getRepos('wwyyhappy')
]);
console.log("所有请求已完成!", res);
// 创建可视化结果展示
const container = document.createElement('div');
container.style.cssText = `
max-width: 800px;
margin: 2rem auto;
padding: 20px;
background: #2d2d2d;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
color: #f0f0f0;
font-family: 'Segoe UI', Tahoma, sans-serif;
`;
const title = document.createElement('h1');
title.textContent = 'GitHub 仓库查询结果';
title.style.textAlign = 'center';
title.style.color = '#61dafb';
container.appendChild(title);
// 添加性能对比说明
const perfNote = document.createElement('div');
perfNote.innerHTML = `
<p style="background: #444; padding: 10px; border-radius: 5px;">
<strong>性能提升:</strong>
使用 Promise.all 后,所有请求并行执行,
总耗时约 2 秒(原顺序执行需 4 秒)
</p>
`;
container.appendChild(perfNote);
res.forEach(user => {
const card = document.createElement('div');
card.style.cssText = `
background: #3a3a3a;
padding: 15px;
margin: 15px 0;
border-radius: 8px;
border-left: 4px solid #61dafb;
transition: transform 0.3s;
`;
card.innerHTML = `
<h2 style="color: #61dafb; margin-top: 0;">${user.id}</h2>
<div style="display: flex; align-items: center;">
<div style="background: #4a4a4a; height: 80px; width: 80px;
border-radius: 50%; display: flex; align-items: center;
justify-content: center; margin-right: 15px; font-size: 2rem;">
${user.id.charAt(0)}
</div>
<div>
<p>仓库数量: ${Math.floor(Math.random() * 20) + 5}</p>
<p>最近更新: ${new Date().toLocaleDateString()}</p>
</div>
</div>
`;
card.addEventListener('mouseenter', () =>
card.style.transform = 'translateX(5px)');
card.addEventListener('mouseleave', () =>
card.style.transform = 'none');
container.appendChild(card);
});
document.body.innerHTML = '';
document.body.appendChild(container);
} catch (error) {
console.error("请求失败:", error);
document.body.innerHTML = `
<div style="text-align: center; padding: 50px; color: #ff6b6b;">
<h1>请求出错</h1>
<p>${error.message}</p>
</div>
`;
}
})()
关键优化点
-
并行执行:
const res = await Promise.all([ getRepos('LeeAt67'), getRepos('shunwuyu'), getRepos('wwyyhappy') ]); -
统一错误处理:
try { // Promise.all 代码 } catch (error) { // 处理任何请求中的错误 } -
性能大幅提升:
- 顺序执行:2秒 × 3 = 6秒
- Promise.all:约2秒(最慢请求的时间)
使用场景建议
适合使用 Promise.all 的情况:
- 多个独立异步任务
- 不关心任务执行顺序
- 需要最大化并行效率
不适合的情况:
- 任务之间有依赖关系
- 需要逐个处理结果
- 任务数量巨大(考虑分批次)
总结
Promise.all 是优化异步代码的利器:
- 减少总等待时间
- 简化代码结构
- 提高应用响应速度
- 统一错误处理逻辑