530 字
3 分钟
异步任务如何控制并发数?
2025-08-07
promise-limit
加载中...

背景#

假设我们有一个图片预加载的需求,但是我们需要控制图片预加载时的请求并发量,请设计一个函数实现上述功能。

实现#

我们的思路:

  1. 首先我们会设计一个函数来执行异步任务,然后设计一个 limit 的变量来控制最大并发量,然后我们使用一个任务池来存储档期的任务,当任务池中的数量达到最大并发量时,我们 await Promise.race有结束的任务即可。

代码实现如下:

async function doSomething(tasks: (() => Promise<void>)[], limit = 2) {
// 正在执行的任务池
// 任务池使用set来做主要是方便删除当前的任务
const pool = new Set();
for (const task of tasks) {
// 执行任务
const promise = task();
// 任务池中增加当前任务
pool.add(promise);
// 当前任务结束时任务池中删除该任务
promise.then(() => pool.delete(promise));
// 当任务池中任务数量达到并发上限时需要等待任务池中任务结束一个才继续执行下一个任务
if (pool.size >= limit) {
await Promise.race(pool);
}
}
// 最后的任务池中的任务执行完毕
return Promise.all(pool);
}
const sleep = (timeout: number, taskName: string) => {
return new Promise<void>(resolve => {
console.log(`${taskName}start`);
setTimeout(() => {
console.log(`${taskName}end`);
resolve();
}, timeout);
});
};
const tasks = [
() => sleep(1000, '吃饭'),
() => sleep(1000, '打游戏'),
() => sleep(3000, '写代码'),
() => sleep(5000, '睡觉'),
() => sleep(7000, '锻炼身体'),
];
doSomething(tasks, 4).then(() => console.log('全部结束了'));
  • 上述代码中的 tasks 任务队列可以替换成真实的图片请求即可,上述代码不变,新增代码如下:
function getLoadImagesTasks(urls: string[]) {
const tasks: (() => Promise<void>)[] = [];
urls.forEach(url => {
tasks.push(
() =>
new Promise<void>(resolve => {
const img = new Image();
console.log(url + 'start');
img.onload = () => {
console.log(url + 'end');
resolve();
};
img.src = url;
// error 场景暂不考虑
})
);
});
return tasks;
}
const urls = [
'https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg',
'https://www.kkkk1000.com/images/getImgData/gray.gif',
'https://www.kkkk1000.com/images/getImgData/Particle.gif',
'https://www.kkkk1000.com/images/getImgData/arithmetic.png',
'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif',
'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg',
'https://www.kkkk1000.com/images/getImgData/arithmetic.gif',
'https://www.kkkk1000.com/images/wxQrCode2.png',
];
doSomething(getLoadImagesTasks(urls), 2).then(() => console.log('全部结束了'));
  • 至此我们的控制并发数量的异步任务已经完成了,可以通过修改 limit 参数来控制异步任务的并发数量,达到了可控的效果。
异步任务如何控制并发数?
https://www.zhaoyuqi.top/posts/promise-limit/
作者
爱哭的赵一一
发布于
2025-08-07
许可协议
CC BY-NC-SA 4.0