1. 并发下载器
实现一个 带请求池限制的并发下载器(下载多个请求,每次最多并发 n 个) ,比如最多同时发出 5 个请求,完成一个就发下一个,总共发 20 个。
✅ 目标理解
download(url, params):异步下载函数,返回一个 Promiserequest({ pool: 5 }):限制最大并发数为 5 的请求调度器for (let i = 0; i < 20; i++):模拟 20 个请求任务- 实现类似
请求池的功能(并发控制)
工作机制
requestAjax是一个包装函数,接受一个返回 Promise 的函数(即下载任务)。- 同时最多运行
pool个任务(这里是 5) - 多余的任务会排队,等前面任务完成后自动执行
// 模拟一个下载函数,返回一个 Promise,模拟异步请求
const download = (url, params) => {
return new Promise((resolve, reject) => {
// 模拟网络请求延迟
setTimeout(() => {
resolve(`下载成功: ${url}`);
}, 1000);
});
};
// 实现请求池控制函数,限制并发数量
function request({ pool = 5 }) {
let activeCount = 0; // 当前正在执行的任务数量
const queue = []; // 等待中的任务队列
// 尝试从队列中取出任务执行
const runNext = () => {
if (queue.length === 0 || activeCount >= pool) return; // 无任务或达到并发上限就不执行
const { fn, resolve, reject } = queue.shift(); // 从队列中取出一个任务
activeCount++; // 当前活跃任务数 +1
fn() // 执行任务函数(必须返回 Promise)
.then(resolve) // 成功后调用传入的 resolve
.catch(reject) // 失败后调用传入的 reject
.finally(() => {
activeCount--; // 当前任务完成,活跃数 -1
runNext(); // 执行下一个任务(如果有)
});
};
// 返回一个包装函数,接收一个返回 Promise 的函数作为任务
return function (fn) {
return new Promise((resolve, reject) => {
queue.push({ fn, resolve, reject }); // 将任务推入队列
runNext(); // 尝试执行任务
});
};
}
// 创建一个最大并发数为 5 的请求控制器
const requestAjax = request({ pool: 5 });
// 向任务池中添加 20 个下载任务
for (let i = 0; i < 20; i++) {
requestAjax(() => download(`https://example.com/file_${i}.jpg`));
}