实现限并发请求队列时陷入无限循环,求问题排查与解决
问题分析与修复方案
核心问题:同步循环与异步操作的执行时机冲突
你的while循环是同步执行的,但fetchMock返回的Promise属于异步操作。执行流程中出现了致命矛盾:
- 第一次循环时,你取出前3个endpoint,把
limit同步减到0,此时endpoints剩余[4,5]。 - 同步的
while会持续检查endpoints.length > 0(条件一直成立),但此时limit已经是0,代码卡在while里无限空转,根本不会给异步操作的finally回调执行的机会,最终导致内存耗尽崩溃。 - 即便异步操作能执行,原逻辑里的
limit++也无法被同步循环感知,因为循环已经进入死循环状态。
修复后的代码
下面的方案通过维护活跃请求计数器+递归补位的方式,实现“一个请求完成后立即发起下一个”的并发控制:
const requestQueue = (endpoints, callback, limit = 3) => { // 复制原数组,避免修改外部传入的数据源 const queue = [...endpoints]; let activeRequests = 0; const runNext = () => { // 队列空了就终止递归 if (queue.length === 0) return; // 还有可用并发名额时发起请求 if (activeRequests < limit) { activeRequests++; const endpoint = queue.shift(); fetchMock(endpoint) .then(data => callback(data)) .catch(err => callback(err)) .finally(() => { activeRequests--; // 当前请求完成后,立刻启动下一个 runNext(); }); } }; // 初始化启动最多limit个请求 for (let i = 0; i < limit; i++) { runNext(); } }; function fetchMock(endpoint) { // 模拟真实接口的延迟,更直观看到并发控制效果 return new Promise(resolve => { setTimeout(() => resolve(endpoint), 1000); }); } requestQueue([1,2,3,4,5], data => console.log(data));
修复逻辑说明
- 用
activeRequests跟踪当前正在运行的请求数,避免修改原limit参数导致的逻辑混乱 - 每次请求完成后(
finally回调),先减少活跃请求数,再递归调用runNext自动补位下一个请求 - 初始阶段先启动最多
limit个请求,之后保持并发数稳定在设定值 - 复制原数组作为队列,避免修改外部传入的数据源产生副作用
内容的提问来源于stack exchange,提问作者j-0-n-e-z
相关产品推荐
相关产品推荐

