闭包实现的异步流控控制器通过封装maxConcurrency、queue和running等私有状态,提供control、setLimit、clearQueue、status等接口,支持并发限制、任务排队、动态调优与可观测性,各实例完全隔离。

用闭包实现“异步流控”的并发请求控制器,核心是把并发数限制、任务排队、执行调度和状态清理全部封装在一个作用域内,让每次创建的控制器实例彼此隔离、语义清晰、无需外部协调。
封装固定并发数与任务队列
闭包捕获最大并发数(maxConcurrency)和待执行任务队列(queue),同时维护当前运行中任务数(running)。所有变量不暴露,仅通过返回的控制函数操作:
- 外层工厂函数接收
{ maxConcurrency = 3 }等配置,初始化queue = []、running = 0 - 返回的
control(fn, ...args)函数将任务包装为 Promise 并推入队列 - 内部自动触发
drain():当running 且队列非空时,取出一个任务执行,并递增running
确保任务执行与状态更新原子性
每个任务执行完毕后,必须准确减少计数并继续调度下一个。闭包让 running 和 drain 在同一作用域,避免竞态:
- 在
.then()和.catch()末尾统一调用running--和再次drain() - 不依赖全局变量或共享状态,每个控制器实例的
running独立,哪怕同时控制 API 调用、文件读取、数据库查询三类任务也不冲突 - 例如:
apiLimiter = createConcurrencyController({ maxConcurrency: 5 })和fileLimiter = createConcurrencyController({ maxConcurrency: 2 })完全解耦
支持动态调整与显式终止
真正的流控不是静态阈值,而需响应运行时变化。闭包可暴露可控方法:
-
setLimit(n):更新maxConcurrency,并立即触发drain()尝试释放更多槽位 -
clearQueue():清空待执行任务,适用于页面卸载、请求取消等场景 -
status():返回{ pending: queue.length, running, limit },便于监控或调试 - 所有方法均访问闭包内私有变量,外部无法绕过逻辑直接修改状态
与 AbortSignal 和可观测性自然结合
闭包作用域可同时持有信号、计时器、指标等,让流控不只是“限速”,更是“可观察的限速”:
- 每个入队任务可绑定独立
AbortSignal,超时或主动 abort 时从队列移除,不占用 slot - 记录每项任务的排队时长、执行耗时、是否因限流被延迟,数据保留在闭包内 metrics 对象中
- 错误抛出携带上下文:
new FlowControlError("QUEUE_TIMEOUT", { queuedAt, positionInQueue })











