js promise如何控制异步并发操作量?
在 JavaScript 中控制异步并发操作量(即限制同时执行的异步任务数量)是优化性能和资源管理的关键。以下是多种实现方法及其详细说明:
一、使用 Promise 和队列控制并发
通过自定义队列系统限制并发数,逐步执行任务。
代码实现
async function asyncPool(poolLimit, tasks) {
const executing = new Set(); // 记录正在执行的任务
const results = [];
for (const task of tasks) {
// 如果当前并发数已达上限,等待任意一个任务完成
if (executing.size >= poolLimit) {
await Promise.race(executing);
}
const p = task().then(result => {
executing.delete(p); // 任务完成后从执行队列移除
results.push(result);
return result;
});
executing.add(p); // 将任务加入执行队列
}
// 等待所有剩余任务完成
await Promise.all(executing);
return results;
}
// 使用示例
const tasks = [
() => fetch('url1'),
() => fetch('url2'),
// ...更多任务
];
asyncPool(3, tasks).then(results => {
console.log('所有任务完成:', results);
});
核心逻辑
- 使用
Set记录正在执行的任务。 - 当并发数超过限制时,通过
Promise.race()等待任意一个任务完成。 - 任务完成后更新队列并记录结果。
二、第三方库 p-limit
使用轻量级库 p-limit 快速实现并发控制。
安装与使用
npm install p-limit
import pLimit from 'p-limit';
const limit = pLimit(3); // 最大并发数 3
const tasks = [
limit(() => fetch('url1')),
limit(() => fetch('url2')),
// ...更多任务
];
// 等待所有任务完成
Promise.all(tasks).then(results => {
console.log(results);
});
优点
- 代码简洁,无需手动管理队列。
- 支持动态添加任务。
三、分批次执行(Batch Processing)
将任务拆分成多个批次,逐批执行。
代码实现
async function batchProcess(tasks, batchSize) {
const results = [];
for (let i = 0; i < tasks.length; i += batchSize) {
const batch = tasks.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(task => task()));
results.push(...batchResults);
}
return results;
}
// 使用示例
const tasks = [
() => fetch('url1'),
() => fetch('url2'),
// ...更多任务
];
batchProcess(tasks, 3).then(results => {
console.log('所有批次完成:', results);
});
缺点
- 前一批次全部完成后才会执行下一批次,资源利用率较低。
四、基于 Promise 的手动调度
通过递归或循环动态启动任务。
代码实现
function controlledConcurrency(tasks, concurrency) {
let index = 0;
const results = [];
// 递归执行任务
const runTask = async () => {
if (index >= tasks.length) return;
const taskIndex = index++;
const task = tasks[taskIndex];
try {
results[taskIndex] = await task();
} catch (error) {
results[taskIndex] = error;
}
await runTask(); // 继续执行下一个任务
};
// 启动初始的并发任务
const workers = Array.from(
{ length: Math.min(concurrency, tasks.length) },
() => runTask()
);
return Promise.all(workers).then(() => results);
}
// 使用示例
controlledConcurrency(tasks, 3).then(results => {
console.log('所有任务完成:', results);
});
五、使用 async-pool 库
专为并发控制设计的库,支持灵活配置。
安装与使用
npm install async-pool
import asyncPool from 'async-pool';
const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function run() {
const tasks = Array.from({ length: 10 }, (_, i) => () => timeout(1000).then(() => i));
const results = await asyncPool(3, tasks);
console.log(results); // [0, 1, 2, 3, ...]
}
run();
六、浏览器环境中的 Promise.withResolvers()(ES2024+)
利用最新的 JavaScript 特性简化代码。
async function controlledConcurrency(tasks, concurrency) {
const results = [];
const queue = [...tasks];
const workers = Array.from({ length: concurrency }, async () => {
while (queue.length) {
const task = queue.shift();
const { promise, resolve, reject } = Promise.withResolvers();
try {
const result = await task();
results.push(result);
resolve(result);
} catch (error) {
reject(error);
}
await promise;
}
});
await Promise.all(workers);
return results;
}
总结
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 手动队列控制 | 需要精细控制逻辑 | 灵活,无依赖 | 代码复杂度高 |
p-limit |
快速实现并发控制 | 简洁,社区维护 | 需安装第三方库 |
| 分批次执行 | 简单分批任务 | 实现简单 | 资源利用率低 |
| 手动调度 | 动态任务管理 | 灵活控制任务启动顺序 | 需处理递归逻辑 |
async-pool |
需要现成解决方案 | 功能丰富 | 需安装第三方库 |
根据需求选择:
- 简单场景:使用
p-limit或分批次执行。 - 精细控制:手动队列或递归调度。
- 最新特性:ES2024 的
Promise.withResolvers()。

浙公网安备 33010602011771号