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

Promise的allSettled,all,race

下列代码证实了:无论是for或是for of循环, 都会等上一个请求彻底完成,才会开始下一个

 // 模拟一个获取用户数据的api请求
function fetchUser(id){
return new Promise(resolve=>{
setTimeout(() =>{
console.log(`获取到用户${id}`);// 模拟网络请求resolve({id: id,name:`用户${id}`});},1000);// 假设每个请求需要1秒钟});
}// 错误做法:在循环里一个接一个地等
async function getAllUsers(userIds){
console.time('获取所有用户耗时');
const users = [];
//无论是for或是for of,都会等上一个请求彻底完成,才会开始下一个
// for(const id of userIds) {
// // 关键问题:这里会停下来等,等上一个请求彻底完成,才会开始下一个
// const user =await fetchUser(id);
//   users.push(user);
//  }for(let i=0;i<userIds.length;i++){const user =await fetchUser(userIds[i]);users.push(user);}
console.timeEnd('获取所有用户耗时'); 
return users;
}const userIds = [1,2,3,4,5];
getAllUsers(userIds);
// 控制台输出:获取所有用户耗时: 约5000毫秒

Promise.race: 只要数组里有一个Promise完成(无论是成功还是失败),它就立刻完成,结果或错误就是那个最快的Promise的。

适合做超时控制或者从多个来源取最快响应(比如测哪个CDN快)。

async function getFirstResponse(){const timeoutPromise =new Promise((_, reject) =>setTimeout(() =>reject(new Error('超时!')),500));const dataPromise = new Promise((resolve, _) =>setTimeout(() =>resolve(123),1500));try{const result =await Promise.race([dataPromise, timeoutPromise]);console.log('成功获取数据:', result);}catch(error) {console.log('出错或超时:', error);}
}
getFirstResponse()

Promise.any: 等待第一个成功完成的Promise。只有数组里所有的Promise都失败了,它才失败。适合需要尝试多个途径,只要有一个成功就行。

async function getFromAnySource(sources) {
try {
const firstSuccess = await Promise.any(sources.map(source => fetch(source)));
console.log('从最快成功的源获取:', firstSuccess);} catch (errors) { // 注意:错误是 AggregateError
console.log('所有源都失败了:', errors);}
}

Promise.allSettled:每个都要结果,不管成功失败
如果有些请求可能会失败,但你不想让一个失败就中断所有,还想知道每个请求最终是成功还是失败了,用Promise.allSettled。

本例中,fetch后面都用catch接住,所以allSettled里的结果都视作成功的结果
const apiRequests = [fetch("https://api.example.com/data1").catch(e=>e),fetch("https://api.example.com/data2").catch(e=>e),fetch("https://api.example.com/data3").catch(e=>e),
];Promise.allSettled(apiRequests).then(results => {const successfulData = results.filter(result => result.status === "fulfilled").map(result => result.value);const errors = results.filter(result => result.status === "rejected").map(result => result.reason);console.log("Successful responses:", successfulData);console.log("Errors:", errors[0]);});

控制同时请求的数量:别把服务器压垮
如果你的用户ID列表有1000个,用Promise.all会瞬间发出1000个请求。

这可能会让你的服务器崩溃,或者被浏览器限制(浏览器通常对同一域名有并发请求数限制,比如6-8个)。

这时候你需要一个“池子”来控制同时进行的请求数量。这里提供一个简单但有效的实现方法:

  async function runWithConcurrency(tasks, maxConcurrent) {
const results = []; // 存放所有任务的最终结果(Promise)
const activeTasks = []; // 当前正在执行的任务对应的Promise(用于跟踪)for (const task of tasks) {
// 1. 创建代表当前任务的Promise。`() => task()` 确保任务在需要时才启动
const taskPromise = Promise.resolve().then(task);results.push(taskPromise); // 保存结果,最后统一用 Promise.all 等// 2. 创建任务完成后的清理操作:从 activeTasks 中移除自己
const removeFromActive = () => activeTasks.splice(activeTasks.indexOf(removeFromActive), 1);activeTasks.push(removeFromActive); // 注意:这里存的是清理函数对应的Promise// 3. 如果当前活跃任务数已达上限,就等任意一个完成
if (activeTasks.length >= maxConcurrent) {
await Promise.race(activeTasks); // 等 activeTasks 数组里任意一个Promise完成}// 4. 将清理操作与实际任务完成挂钩taskPromise.then(removeFromActive, removeFromActive); // 无论成功失败都清理}// 5. 等待所有任务完成(无论是否在活跃池中)
return Promise.allSettled(results); // 或者用 Promise.all(results) 只关心成功
}// 使用示例
const userIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 将 fetchUser(id) 调用包装成无参数的函数数组
const tasks = userIds.map(id =>() => fetchUser(id));// 最多同时发出 3 个请求
runWithConcurrency(tasks, 3).then(results => {
console.log('所有用户获取完成 (并发控制):', results);
});

这个函数会确保最多只有maxConcurrent个请求同时在进行。

当一个请求完成,池子里有空位了,才会开始下一个请求。在实际项目中,你也可以使用成熟的库如 p-limit 或 async 的 queue 方法来实现更强大的并发控制。

http://www.dtcms.com/a/298101.html

相关文章:

  • RCE真实漏洞初体验
  • CGA老年综合评估汉密尔顿抑郁量表与认知评估联用
  • HTML 常用标签速查表
  • 智能机器人的技术革命:从感知到决策的全栈架构解析
  • 目前市面上arm64-v8a、armeabi-v7a设备的市占率有多少?为什么x86架构的手机越来越少?
  • 如何识别发票特殊版式?OCR大模型如何颠覆传统并保证准确率?
  • 力扣面试150(41/150)
  • 力扣-560.和为K的子数组
  • 第 9 篇:神经网络初探——当AI拥有了“大脑”,世界从此不同
  • JAVA语法糖
  • 高效算法的实现与优化是计算机科学的核心,直接决定了程序的性能和资源消耗。下面针对排序算法、搜索算法和动态规划,深入探讨其高效实现与关键优化技术。
  • 机器视觉对位印刷加工PCB板应用
  • LlamaIndex 和 Elasticsearch Rerankers:无与伦比的简洁
  • Power Compiler:漏电功耗、内部功耗、切换功耗及其计算方式(NLPM)
  • 基于Transform、ARIMA、LSTM、Prophet的药品销量预测分析
  • Jenkins中HTML文件显示样式问题解决方案
  • 【数据库】AI驱动未来:电科金仓新一代数据库一体机如何重构性能边界?
  • Vue接口平台十二 —— 测试任务(Task)
  • CentOS7 安装 Redis
  • ThreadLocal使用及其原理和注意点
  • 背包DP之完全背包
  • MCP (Model Context Protocol) 与 HTTP API:大模型时代的通信新范式
  • 如何在windows设置Redis服务后台自启动
  • Hive【安装 01】hive-3.1.2版本安装配置(含 mysql-connector-java-5.1.47.jar 网盘资源)
  • 数据管理能力成熟度评估模型(DCMM)详解
  • 基于Matlab图像处理的瓶子自动检测与质量评估系统
  • SpringBoot整合Fastexcel/EasyExcel导出Excel导出多个图片
  • QKV 为什么是三个矩阵?注意力为何要除以 √d?多头注意力到底有啥用?
  • MyBatis 之缓存机制核心解析
  • android JXL 导出Excel(.xls/xlsx)