通过维护一个并发计数器并在发起请求前检查该计数器的值,可以实现 fetch api 的请求数据预限流策略。具体做法是定义一个最大并发数上限,在每次调用 fetch 之前判断当前活跃请求数是否达到上限,若未达到则直接发送并增加计数,若已达到则等待直到有请求完成释放资源后再重试,从而确保同时进行的网络请求不会超过设定阈值。

如何构建支持队列的限流控制器
构建限流控制器的核心在于管理一个任务队列和一个当前活跃计数的状态机。当用户尝试发起请求时,如果当前活跃数小于最大限制,任务立即执行;否则,任务被推入等待队列。一旦某个请求结束(无论成功或失败),控制器会从队列中取出下一个任务并执行,同时递减活跃计数。这种机制保证了系统负载始终处于可控范围内。

class RateLimiter {
constructor(maxConcurrent) {
this.maxConcurrent = maxConcurrent;
this.currentRequests = 0;
this.queue = [];
}
async addRequest(requestFn) {
return new Promise((resolve, reject) => {
const execute = async () => {
if (this.currentRequests 0 && this.currentRequests {
this.currentRequests--;
this.processQueue();
});
}
}
}
// 使用示例
const limiter = new RateLimiter(3);
const urls = Array.from({ length: 10 }, (_, i) => `https://api.example.com/data/${i}`);
Promise.all(urls.map(url =>
limiter.addRequest(() => fetch(url).then(r => r.json()))
)).then(results => console.log('All done', results));
上述代码定义了一个 RateLimiter 类,它接收最大并发数作为参数。其 addRequest 方法返回一个 Promise,内部逻辑判断当前请求数是否低于上限。如果低于上限,则立即执行请求函数并递增计数器;如果达到上限,则将包含解析、拒绝和请求函数的对象推入 queue 数组。当任何请求完成时,finally 块会触发 processQueue 方法,该方法循环检查队列,如果有空闲槽位且队列不为空,则取出下一个任务执行。这种实现方式确保了即使传入大量请求,同一时刻只有指定数量的请求在并行处理。
如何处理请求取消与错误恢复
在实际应用中,用户可能会在请求排队期间取消操作,或者网络请求本身可能失败。限流器需要能够正确处理这些情况,避免内存泄漏或死锁。通过在任务对象中存储 AbortController 实例,可以在外部调用取消方法时中断正在等待或正在进行的请求。同时,错误处理必须确保无论请求成功还是失败,计数器都会正确递减,并且队列会继续处理后续任务,不会因为单个错误而停滞。

class RobustRateLimiter extends RateLimiter {
constructor(maxConcurrent) {
super(maxConcurrent);
this.abortControllers = new Map();
}
addRequestWithCancel(requestFn, requestId) {
const controller = new AbortController();
this.abortControllers.set(requestId, controller);
const wrappedRequest = () => {
// 移除已完成的控制器引用
if (!this.abortControllers.has(requestId)) return Promise.resolve(null);
return requestFn({ signal: controller.signal });
};
const promise = super.addRequest(wrappedRequest).finally(() => {
this.abortControllers.delete(requestId);
});
// 绑定取消方法
promise.cancel = () => {
controller.abort();
this.abortControllers.delete(requestId);
// 从队列中移除未开始的任务(简化处理,实际需遍历队列)
};
return promise;
}
}
// 验证错误恢复
const limiter = new RobustRateLimiter(2);
limiter.addRequest(() => fetch('https://invalid-url.com').catch(e => ({ error: true })))
.then(res => console.log('Error handled gracefully', res));
扩展后的 RobustRateLimiter 继承自基础限流器,增加了 AbortController 的管理能力。每个请求关联一个唯一的 requestId,用于追踪对应的中止控制器。在 addRequestWithCancel 中,原始请求函数被包装,注入 signal 以便底层 fetch 支持取消。当请求结束时,finally 钩子清理映射表中的控制器引用。如果用户在等待期间调用 cancel(),控制器会被中止,fetch 抛出异常,但限流器的错误捕获逻辑会确保计数器递减并继续处理队列中的其他任务,从而维持系统的稳定性。这种设计使得限流策略不仅关注并发数量,还兼顾了请求的生命周期管理。
基于特定输入条件下的并发行为分析
当输入条件为高频率短生命周期请求时,限流器的队列积压现象最为明显。例如,当一次性提交 100 个耗时仅 50ms 的请求,而最大并发设为 2 时,队列将迅速填满。此时,观察到的行为是请求以每批 2 个的速度快速流转,总耗时接近于串行执行的总和除以并发度。这种场景下,预限流策略有效防止了浏览器因过多并发连接导致的线程阻塞或服务器端限流响应,证明了其在高频场景下的必要性。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











