async/await本身不提供并发限制,但最适合实现并发控制,常用方式包括asyncpool封装并发池、类封装请求队列、分批+promise.all及信号量机制。

async/await 本身不直接提供并发限制能力,但它是最适合实现并发控制的语法基础。关键在于把“限制同时执行的任务数”这个逻辑,用 Promise 链、队列或信号量结构组织起来,再用 async/await 让代码清晰可读。
用 asyncPool 封装并发池
这是最常用也最实用的方式:把一批异步任务放进一个“池子”,设定最大并发数(比如 3),自动排队执行。
- 每次只让最多 max 个任务真正运行;
- 新任务进来时,如果当前运行中任务数未达上限,立即执行;否则进等待队列;
- 任一任务完成,就从队列里取出下一个执行。
示例代码结构:
async function asyncPool(poolLimit, array, iteratorFn) {
const ret = [];
const executing = [];
for (const item of array) {
const promise = Promise.resolve().then(() => iteratorFn(item));
ret.push(promise);
if (poolLimit executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) {
await Promise.race(executing);
}
}
}
return Promise.all(ret);
}
// 使用
const urls = ['/api/1', '/api/2', ..., '/api/100'];
const results = await asyncPool(5, urls, url => fetch(url).then(r => r.json()));
用类封装请求队列
适合需要复用、动态调整并发数或添加重试/优先级的场景。核心是维护 运行中数量 和 待执行队列。
- 调用
add(requestFn)时,不立即执行,而是入队; - 内部
_dequeue()方法检查是否还能启动新任务; - 每个任务完成后,自动触发下一轮调度。
这样能保证任意时刻最多只有指定数量的 fetch 在进行,不会因数组过大导致内存或连接耗尽。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
分批 + Promise.all 控制(适合简单批量)
如果任务彼此独立、无依赖,且不需要精细调度,用数组分块最直观。
- 把 100 个 URL 每 6 个一组,拆成 17 个批次;
- 用
for...of循环逐批await Promise.all(batchPromises); - 每批最多发 6 个请求,天然限流。
优点是逻辑透明、调试方便;缺点是无法“空出一个槽位就补上”,吞吐略低,但对多数导出、上传等场景已足够。
信号量(Semaphore)模拟资源锁
更底层的控制方式,适合需要跨函数、跨模块共享并发配额的场景。
- 定义一个
Semaphore类,带acquire()和release(); - 每个请求前先
await sem.acquire(),成功才发起 fetch; - fetch 完成后必须调用
sem.release(),否则队列会卡死。
这种方式像操作系统里的信号量,语义明确,也便于扩展超时、取消等功能。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










