闭包实现的并发调度器通过封装running和pending队列,限制同时执行Promise数量并按FIFO顺序调度:createScheduler(max)返回add方法,接收返回Promise的函数而非Promise本身,内部用runNext自动启任务,finally安全清理并续调。

用闭包实现一个支持并发控制的异步调度器,核心是维护一个“正在运行的任务队列”和一个“等待中的任务队列”,并通过闭包捕获并管理这些状态,避免全局污染。关键在于:限制同时执行的 Promise 数量,自动从等待队列中取任务补充,且保证任务按添加顺序尽可能早地开始执行(FIFO)。
闭包封装调度状态与方法
用立即执行函数返回一组操作方法,内部变量(如 max、running、pending)被闭包保护,外部无法直接修改:
function createScheduler(max) {
const running = []; // 当前正在执行的 Promise
const pending = []; // 等待执行的任务函数数组
function runNext() {
if (pending.length === 0 || running.length >= max) return;
const task = pending.shift();
const p = task();
running.push(p);
p.finally(() => {
const idx = running.indexOf(p);
if (idx > -1) running.splice(idx, 1);
runNext(); // 尝试启动下一个
});
}
return {
add: (task) => {
pending.push(task);
runNext();
}
};
}
使用方式:add 方法传入返回 Promise 的函数
注意不是直接传 Promise,而是传一个“能生成 Promise 的函数”,否则任务会在 add 时就立即执行,失去调度意义:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
const scheduler = createScheduler(2);
scheduler.add(() => fetch('/api/a').then(res => res.json()));
scheduler.add(() => fetch('/api/b').then(res => res.json()));
scheduler.add(() => new Promise(r => setTimeout(() => r('c'), 1000)));
scheduler.add(() => fetch('/api/d').then(res => res.json()));
// 最多同时进行 2 个 fetch,第 3 个等前两个任一完成才开始
支持链式调用与任务完成通知(可选增强)
可在返回对象中增加 onIdle 或返回 Promise 的 execute 方法,让调用方感知全部完成:
立即学习“Java免费学习笔记(深入)”;
- 加一个 idlePromise 和 resolveIdle,每次 running 变空时 resolve 它;下次 add 时重新创建
- 或让 add 返回一个 Promise,当该任务实际执行完毕后才 resolve(需在 finally 里判断是否是它自己)
- 不建议在闭包内维护太多状态,保持主干逻辑清晰更重要
注意事项与常见坑
闭包虽好,但要注意几个易错点:
- 不要把 Promise 直接 push 到 pending —— 必须是函数,否则并发数控制失效
- finally 中要安全移除 running 中的 Promise —— 用 indexOf + splice 比用 filter 更准(避免重复引用或 Promise 已被 GC)
- runNext 是递归触发,但不会栈溢出 —— 因为每次都是异步回调(finally 是微任务),实际是事件循环驱动
- 如果任务函数抛出同步错误,需在外层 try/catch 并调用 runNext(),否则队列会卡住

















