能否实现支持动态数组的有限并发Promise并行执行?
动态Promise并发控制实现方案
可行性结论
完全可以实现,这种需求属于带动态任务补充的并发限流场景,核心是维护任务池与待处理队列,在任务完成时自动补入新任务,无需依赖Promise.all或Promise.race的原生行为。
核心实现思路
- 维护两个核心状态:
- 待处理URL队列:存储待请求的URL,支持动态追加
- 当前并发任务数:实时跟踪运行中的请求数量,确保不超过设定上限(100)
- 实现任务启动器:当当前并发数小于上限且队列非空时,取出队列头部URL发起请求
- 任务完成回调:每个请求结束(无论成功/失败)后,递减并发数,并再次触发任务启动逻辑,补入新任务
- 动态URL处理:只要向待处理队列追加URL,任务启动器会自动检测并启动新任务,无需额外触发逻辑
代码示例
class ConcurrentFetcher { constructor(maxConcurrency = 100) { this.maxConcurrency = maxConcurrency; this.urlQueue = []; this.activeTasks = 0; this.results = []; } // 添加URL到队列,支持单个或批量添加 addUrls(urls) { if (Array.isArray(urls)) { this.urlQueue.push(...urls); } else { this.urlQueue.push(urls); } // 添加后尝试启动新任务 this._startTasks(); } // 核心任务启动逻辑 async _startTasks() { // 循环启动任务,直到达到并发上限或队列为空 while (this.activeTasks < this.maxConcurrency && this.urlQueue.length > 0) { const url = this.urlQueue.shift(); this.activeTasks++; this._handleFetch(url).finally(() => { this.activeTasks--; // 当前任务结束后,递归启动新任务 this._startTasks(); }); } } // 单个URL的请求处理 async _handleFetch(url) { try { const response = await fetch(url); const data = await response.json(); this.results.push({ url, success: true, data }); console.log(`完成请求: ${url}`); } catch (error) { this.results.push({ url, success: false, error: error.message }); console.error(`请求失败: ${url}`, error.message); } } // 获取所有结果(适用于有限队列,无限队列可忽略此方法) async getResults() { // 等待所有活动任务和队列任务完成 while (this.activeTasks > 0 || this.urlQueue.length > 0) { await new Promise(resolve => setTimeout(resolve, 100)); } return this.results; } } // 使用示例 const fetcher = new ConcurrentFetcher(100); // 初始添加215个URL const initialUrls = Array.from({ length: 215 }, (_, i) => `https://example.com/api/item/${i}`); fetcher.addUrls(initialUrls); // 动态添加新URL(比如10秒后追加) setTimeout(() => { const newUrls = Array.from({ length: 5 }, (_, i) => `https://example.com/api/new/${i}`); fetcher.addUrls(newUrls); console.log("已追加5个新URL"); }, 10000); // 如果是有限队列,可在最后获取结果 // fetcher.getResults().then(results => { // console.log("所有请求完成", results); // });
关键细节说明
- 规避
Promise.race缺陷:每个任务独立处理完成逻辑,不会中断其他运行中的任务,所有请求都会被完整执行 - 动态队列适配:
addUrls方法可随时调用,追加的URL会自动进入等待队列,在并发数有空位时启动 - 错误隔离:单个请求失败不会影响其他任务执行,失败结果会被记录到
results数组中 - 无限队列支持:若URL队列是无限的,只需持续调用
addUrls追加即可,控制器会一直维持最大并发数运行
内容的提问来源于stack exchange,提问作者forty5
相关产品推荐
相关产品推荐

