在前端开发中,经常需要控制并发请求的数量以避免服务器过载或浏览器性能问题。下面我使用 Promise 实现一个请求队列控制器。
基本思路:
- 维护一个等待队列和一个执行队列
- 当有新的请求加入时,先放入等待队列
- 当执行队列有空位时,从等待队列取出请求执行
- 请求完成后,从执行队列移除,并检查是否有等待的请求
js
class PromiseQueue {
constructor(limit = 2) {
this.limit = limit;
this.running =0;
this.queue=[];
}
add(fn)
{
return new Promise((resolve, reject) => {
const executeFn = async () => {
this.running++;
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.next();
}
};
this.queue.push(executeFn);
this.next();
});
}
next() {
if ( this.queue.length && this.running < this.limit ) {
const fn = this.queue.shift();
fn();
}
}
}
测试用例
js
// 测试代码
async function testPromiseQueue() {
// 1. 创建一个最大并发数为2的队列
const queue = new PromiseQueue(2);
const results = [];
const startTime = Date.now();
// 辅助函数:创建一个带延迟的测试任务
const createTask = (id, delay, shouldFail = false) => async () => {
const start = Date.now() - startTime;
console.log(`任务 ${id} 开始执行 (延迟 ${delay}ms) [时间: ${start}ms]`);
await new Promise(resolve => setTimeout(resolve, delay));
if (shouldFail) {
throw new Error(`任务 ${id} 模拟失败`);
}
console.log(`任务 ${id} 完成 (耗时 ${delay}ms) [时间: ${Date.now() - startTime}ms]`);
return id;
};
// 2. 添加测试任务
// 快速任务 (100ms)
queue.add(createTask(1, 100))
.then(res => results.push(`任务1成功: ${res}`))
.catch(err => results.push(`任务1失败: ${err.message}`));
// 慢速任务 (200ms)
queue.add(createTask(2, 200))
.then(res => results.push(`任务2成功: ${res}`))
.catch(err => results.push(`任务2失败: ${err.message}`));
// 快速失败任务 (100ms)
queue.add(createTask(3, 100, true))
.then(res => results.push(`任务3成功: ${res}`))
.catch(err => results.push(`任务3失败: ${err.message}`));
// 超慢速任务 (300ms)
queue.add(createTask(4, 300))
.then(res => results.push(`任务4成功: ${res}`))
.catch(err => results.push(`任务4失败: ${err.message}`));
// 快速任务 (100ms)
queue.add(createTask(5, 100))
.then(res => results.push(`任务5成功: ${res}`))
.catch(err => results.push(`任务5失败: ${err.message}`));
// 3. 等待所有任务完成
await new Promise(resolve => setTimeout(resolve, 1000));
// 4. 打印测试结果
console.log('\n最终结果:');
console.log(results.sort().join('\n'));
// 5. 验证并发数是否正确
console.log('\n验证:');
console.log(`最大并发数: ${queue.limit}`);
console.log(`运行中任务数: ${queue.running}`);
console.log(`队列中剩余任务: ${queue.queue.length}`);
}
// 执行测试
testPromiseQueue();