当前位置: 首页 > news >正文

Promise.all和Promise.race的区别

Promise.all 和 Promise.race 的区别

基本概念对比

特性Promise.allPromise.race
执行机制等待所有Promise完成只要有一个Promise完成就返回
返回值所有Promise结果的数组第一个完成的Promise结果
错误处理有一个失败立即拒绝第一个完成的(成功或失败)
适用场景并行处理,需要所有结果竞速,超时控制,最快响应

详细解析

1. Promise.all

特点: 等待所有Promise完成,全部成功才算成功,有一个失败立即失败

// 基本用法
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);Promise.all([promise1, promise2, promise3]).then(results => {console.log(results); // [1, 2, 3]}).catch(error => {console.error('有一个Promise失败了:', error);});

成功案例:

const urls = ['/api/user', '/api/posts', '/api/settings'];// 并行请求多个接口
Promise.all(urls.map(url => fetch(url))).then(responses => {// 所有请求都成功完成return Promise.all(responses.map(response => response.json()));}).then(data => {console.log('用户数据:', data[0]);console.log('文章数据:', data[1]);console.log('设置数据:', data[2]);}).catch(error => {console.error('某个请求失败了:', error);});

失败案例:

const promise1 = Promise.resolve('成功1');
const promise2 = Promise.reject('失败啦!');
const promise3 = Promise.resolve('成功3');Promise.all([promise1, promise2, promise3]).then(results => {console.log(results); // 不会执行到这里}).catch(error => {console.error('捕获到错误:', error); // "失败啦!"});

2. Promise.race

特点: 竞速模式,哪个Promise先完成就返回哪个的结果

// 基本用法
const promise1 = new Promise((resolve) => {setTimeout(() => resolve('第一个完成'), 1000);
});const promise2 = new Promise((resolve) => {setTimeout(() => resolve('第二个完成'), 500);
});Promise.race([promise1, promise2]).then(result => {console.log(result); // "第二个完成" (因为500ms比1000ms快)}).catch(error => {console.error('第一个完成的Promise失败了:', error);});

实际应用场景

Promise.all 应用场景

1. 并行处理多个独立任务
// 同时获取用户信息和订单信息
function getUserDashboard(userId) {const userPromise = fetch(`/api/users/${userId}`);const ordersPromise = fetch(`/api/users/${userId}/orders`);const settingsPromise = fetch(`/api/users/${userId}/settings`);return Promise.all([userPromise, ordersPromise, settingsPromise]).then(responses => Promise.all(responses.map(r => r.json()))).then(([user, orders, settings]) => {return {user,orders,settings};});
}
2. 批量数据处理
// 批量上传文件
function uploadFiles(files) {const uploadPromises = files.map(file => {return new Promise((resolve, reject) => {const formData = new FormData();formData.append('file', file);fetch('/api/upload', {method: 'POST',body: formData}).then(response => response.json()).then(resolve).catch(reject);});});return Promise.all(uploadPromises).then(results => {console.log('所有文件上传完成:', results);return results;});
}

Promise.race 应用场景

1. 请求超时控制
// 设置请求超时
function fetchWithTimeout(url, timeout = 5000) {const fetchPromise = fetch(url);const timeoutPromise = new Promise((_, reject) => {setTimeout(() => reject(new Error('请求超时')), timeout);});return Promise.race([fetchPromise, timeoutPromise]);
}// 使用示例
fetchWithTimeout('/api/data', 3000).then(response => response.json()).then(data => console.log('数据:', data)).catch(error => {if (error.message === '请求超时') {console.log('请求超时,显示备用数据');} else {console.error('其他错误:', error);}});
2. 竞速获取资源
// 从多个CDN源获取资源,使用最快的响应
function getFastestResource(resourceUrls) {const fetchPromises = resourceUrls.map(url => fetch(url).then(response => response.json()));return Promise.race(fetchPromises).then(data => {console.log('使用最快响应的数据源');return data;});
}// 使用多个CDN源
const cdnUrls = ['https://cdn1.example.com/data.json','https://cdn2.example.com/data.json','https://cdn3.example.com/data.json'
];getFastestResource(cdnUrls).then(data => {// 使用最快返回的数据
});

高级用法和区别演示

综合对比示例

// 创建测试Promise
const createPromise = (value, delay, shouldReject = false) => {return new Promise((resolve, reject) => {setTimeout(() => {if (shouldReject) {reject(`错误: ${value}`);} else {resolve(`成功: ${value}`);}}, delay);});
};const p1 = createPromise('A', 1000);
const p2 = createPromise('B', 500);
const p3 = createPromise('C', 2000);console.log('=== Promise.all 测试 ===');
Promise.all([p1, p2, p3]).then(results => {console.log('Promise.all 结果:', results);// ["成功: A", "成功: B", "成功: C"] (等待所有完成)}).catch(error => {console.log('Promise.all 错误:', error);});console.log('=== Promise.race 测试 ===');
Promise.race([p1, p2, p3]).then(result => {console.log('Promise.race 结果:', result);// "成功: B" (最快完成的)}).catch(error => {console.log('Promise.race 错误:', error);});

错误处理对比

// 包含错误的Promise测试
const successPromise = createPromise('成功', 1000);
const errorPromise = createPromise('错误', 500, true);
const latePromise = createPromise('迟到的', 2000);console.log('=== Promise.all 错误处理 ===');
Promise.all([successPromise, errorPromise, latePromise]).then(results => {console.log('不会执行这里');}).catch(error => {console.log('Promise.all 捕获错误:', error); // "错误: 错误"// 立即失败,不会等待其他Promise});console.log('=== Promise.race 错误处理 ===');
Promise.race([successPromise, errorPromise, latePromise]).then(result => {console.log('Promise.race 成功:', result);}).catch(error => {console.log('Promise.race 捕获错误:', error); // "错误: 错误"// 第一个完成的(无论成功失败)});

手写实现

手写 Promise.all

Promise.myAll = function(promises) {return new Promise((resolve, reject) => {if (!Array.isArray(promises)) {return reject(new TypeError('参数必须是数组'));}const results = [];let completedCount = 0;if (promises.length === 0) {return resolve(results);}promises.forEach((promise, index) => {Promise.resolve(promise).then(value => {results[index] = value;completedCount++;if (completedCount === promises.length) {resolve(results);}}).catch(reject); // 任何一个失败立即拒绝});});
};

手写 Promise.race

Promise.myRace = function(promises) {return new Promise((resolve, reject) => {if (!Array.isArray(promises)) {return reject(new TypeError('参数必须是数组'));}if (promises.length === 0) {return; // 永远pending}promises.forEach(promise => {Promise.resolve(promise).then(resolve)  // 第一个成功的.catch(reject); // 第一个失败的});});
};

总结表格

方面Promise.allPromise.race
执行策略全部完成竞速完成
返回值结果数组单个结果
成功条件全部成功第一个成功
失败条件任一失败第一个失败
等待时间最慢的完成时间最快的完成时间
内存占用保存所有结果只保存一个结果
典型用途并行计算、批量操作超时控制、竞速请求

使用建议

  1. 使用 Promise.all 当:

    • 需要所有异步操作的结果
    • 操作之间相互独立
    • 可以容忍最慢的操作时间
  2. 使用 Promise.race 当:

    • 只需要最快的结果
    • 实现超时机制
    • 多个备用方案竞争
  3. 注意事项:

    • Promise.all 中一个失败会导致整个失败
    • Promise.race 不保证结果的稳定性
    • 都要做好错误处理

Promise.all 返回顺序与执行顺序的关系

结论

Promise.all 返回结果的顺序与传入的Promise数组顺序完全一致,与执行完成的先后顺序无关。

详细解析

1. 基本行为演示

// 创建不同耗时的Promise
const createPromise = (value, delay) => {return new Promise(resolve => {setTimeout(() => {console.log(`完成: ${value}, 耗时: ${delay}ms`);resolve(value);}, delay);});
};const promise1 = createPromise('第一个', 1000);  // 最慢
const promise2 = createPromise('第二个', 300);   // 最快
const promise3 = createPromise('第三个', 500);   // 中等Promise.all([promise1, promise2, promise3]).then(results => {console.log('最终结果顺序:', results);// 输出: ["第一个", "第二个", "第三个"]// 尽管执行完成顺序是: 第二个 -> 第三个 -> 第一个});// 控制台输出:
// 完成: 第二个, 耗时: 300ms
// 完成: 第三个, 耗时: 500ms  
// 完成: 第一个, 耗时: 1000ms
// 最终结果顺序: ["第一个", "第二个", "第三个"]

2. 实现原理

Promise.all 内部会维护结果的顺序:

// 手写实现,展示顺序保持原理
Promise.myAll = function(promises) {return new Promise((resolve, reject) => {const results = new Array(promises.length);let completedCount = 0;promises.forEach((promise, index) => {Promise.resolve(promise).then(value => {// 关键:根据原始索引存储结果results[index] = value;completedCount++;if (completedCount === promises.length) {resolve(results); // 按原始顺序返回}}).catch(reject);});});
};

3. 实际应用场景

场景1:批量请求保持顺序
// 批量获取用户信息,需要保持返回顺序
const userIds = [1, 2, 3, 4, 5];function getUserInfo(userId) {return fetch(`/api/users/${userId}`).then(response => response.json()).then(user => {console.log(`获取到用户 ${userId} 的数据`);return user;});
}// 尽管网络请求完成时间不同,但结果顺序与 userIds 一致
Promise.all(userIds.map(getUserInfo)).then(users => {// users[0] 对应 userIds[0] 的用户// users[1] 对应 userIds[1] 的用户// 以此类推...console.log('用户顺序保持不变:', users.map(user => user.id));// 输出: [1, 2, 3, 4, 5]});
场景2:文件处理保持顺序
// 批量处理文件,需要保持处理前后的顺序对应
const files = ['file1.txt', 'file2.txt', 'file3.txt'];function processFile(filename, index) {return new Promise(resolve => {const processTime = Math.random() * 1000 + 500; // 随机处理时间setTimeout(() => {console.log(`处理完成: ${filename}, 索引: ${index}`);resolve({originalName: filename,processedName: `processed_${filename}`,index: index});}, processTime);});
}Promise.all(files.map((file, index) => processFile(file, index))).then(processedFiles => {console.log('最终结果顺序:');processedFiles.forEach((file, index) => {console.log(`结果[${index}]: ${file.originalName} -> ${file.processedName}`);});// 尽管处理完成顺序随机,但最终数组顺序与 files 数组一致});

4. 与执行完成顺序的对比

// 明确展示执行顺序 vs 返回顺序
const tasks = [{ name: '任务A', time: 2000 },{ name: '任务B', time: 500 },{ name: '任务C', time: 1000 },{ name: '任务D', time: 300 }
];const promises = tasks.map((task, index) => {return new Promise(resolve => {setTimeout(() => {const completionInfo = {taskName: task.name,originalIndex: index,completedAt: new Date().toISOString()};console.log(`✅ 完成: ${task.name} (原索引: ${index})`);resolve(completionInfo);}, task.time);});
});console.log('开始执行Promise.all...');
console.log('预期返回顺序:', tasks.map(t => t.name));Promise.all(promises).then(results => {console.log('\n📋 最终返回顺序:');results.forEach((result, index) => {console.log(`结果[${index}]: ${result.taskName} (原索引: ${result.originalIndex})`);});console.log('\n⏱️ 实际完成顺序:');const sortedByCompletion = [...results].sort((a, b) => new Date(a.completedAt) - new Date(b.completedAt));sortedByCompletion.forEach((result, index) => {console.log(`${index + 1}个完成: ${result.taskName}`);});});// 输出示例:
// 开始执行Promise.all...
// 预期返回顺序: ["任务A", "任务B", "任务C", "任务D"]
// ✅ 完成: 任务D (原索引: 3)
// ✅ 完成: 任务B (原索引: 1)  
// ✅ 完成: 任务C (原索引: 2)
// ✅ 完成: 任务A (原索引: 0)
//
// 📋 最终返回顺序:
// 结果[0]: 任务A (原索引: 0)
// 结果[1]: 任务B (原索引: 1)
// 结果[2]: 任务C (原索引: 2) 
// 结果[3]: 任务D (原索引: 3)
//
// ⏱️ 实际完成顺序:
// 第1个完成: 任务D
// 第2个完成: 任务B
// 第3个完成: 任务C
// 第4个完成: 任务A

5. 错误情况下的顺序保证

// 即使有Promise失败,已完成的结果顺序仍然保持
const mixedPromises = [Promise.resolve('成功1'),Promise.reject('错误!'),Promise.resolve('成功3'),Promise.resolve('成功4')
];// 在第二个Promise失败前,第一个已经成功,但结果不会包含在错误中
Promise.all(mixedPromises).then(results => {console.log('成功结果:', results);}).catch(error => {console.log('捕获错误:', error); // "错误!"// 注意:即使第一个Promise已经成功完成,我们也不会看到它的结果// 整个Promise.all立即拒绝,不等待其他Promise});

6. 与其他方法的对比

与 Promise.race 对比
const promises = [new Promise(resolve => setTimeout(() => resolve('慢的'), 1000)),new Promise(resolve => setTimeout(() => resolve('快的'), 100))
];// Promise.all - 保持顺序
Promise.all(promises).then(results => {console.log('Promise.all 结果:', results); // ["慢的", "快的"]
});// Promise.race - 只取最快
Promise.race(promises).then(result => {console.log('Promise.race 结果:', result); // "快的"
});
与 Promise.allSettled 对比
// Promise.allSettled 同样保持顺序
const promisesWithErrors = [Promise.resolve('成功1'),Promise.reject('错误2'),Promise.resolve('成功3')
];Promise.allSettled(promisesWithErrors).then(results => {console.log('allSettled 结果顺序:');results.forEach((result, index) => {console.log(`[${index}]:`, result.status, result.value || result.reason);});// 顺序保持: 成功1, 错误2, 成功3});

重要总结

  1. 顺序保证: Promise.all 严格按传入数组顺序返回结果
  2. 索引对应: 结果数组的索引与原始Promise数组索引一一对应
  3. 与执行时间无关: 无论哪个Promise先完成,返回顺序不变
  4. 错误处理: 一旦有Promise失败,立即拒绝,不返回任何成功结果
  5. 适用场景: 需要保持处理前后顺序对应的批量异步操作

这种顺序保证的特性使得 Promise.all 在处理需要保持对应关系的批量操作时非常有用,比如:

  • 批量文件上传后需要与原文件列表对应
  • 多个API请求后需要与请求参数对应
  • 并行计算后需要与输入数据顺序对应
http://www.dtcms.com/a/545829.html

相关文章:

  • 聊城有制作网站的吗甘肃建设厅网站首页
  • 思维类:如何让孩子喜欢阅读
  • 如何编写网站建设销售的心得近10天的时政新闻
  • 百度亮相 SREcon25:搜索稳定背后的秘密,微服务雪崩故障防范
  • 仓颉语言中的MVVM架构实现:响应式数据绑定底层机制深度解析
  • PHP7.4.33 安装sqlsrv扩展
  • 哪个公司要做网络推广常德seo快速排名
  • 置换-选择排序:外存排序的艺术与智慧
  • 遗传算法全局寻优ETF动态止盈参数空间的新范式
  • 玉林建设工程信息网站建立网站买空间哪家好
  • geoserver-manager(java操作geoserver发布服务)
  • 网站不能访问的原因成都市装修公司前十强
  • 前端怎么做网站发布网站需要备案
  • LSS论文阅读
  • 论文阅读——Segment Anything(Meta AI)——SAM
  • 关于网站建设需要了解什么东西个人网站 平台
  • 基于启发式的多模态风险分布越狱攻击,针对多模态大型语言模型(ICCV 2025) - 论文阅读和解析
  • 对我单位网站进行改版wordpress 打包app
  • python使用Pygame库实现避障小人行走游戏
  • 安徽网站建站系统平台百度竞价排名事件分析
  • 餐馆网站怎么做微信开放平台网站应用
  • Docker篇2-用python运行项目和docker运行冲突问题
  • Linux SDIO驱动框架深度解析与技术实践
  • 被禁止访问网站怎么办网站建设怎么支付款项
  • 公司有网站有什么好处东莞网页设计制作公司
  • 做外贸 网站网易免费企业邮箱登录入口
  • 自己怎么做网站免费的做网站用discuz还是wp
  • windows系统连接docker desktop启动的mysql
  • 个人信息网站汾阳网站建设
  • 惠州市两学一做网站网站建设归工商局管还是工信局管