Q:并发请求数量过大,会在短时间内发送大量的网络请求,并且占用大量的系统资源,可能会造成接口阻塞,浏览器卡死现象,怎么才能控制并发请求数量防止频繁渲染呢?
可以考虑使用异步请求池,来控制同一时间并发请求的数量,我们可以通过维护一个请求队列来实现:
1.创建类并维护变量
定义一个PromisePool的类,接收conncurrency参数来控制并发请求的数量;
同时我们需要存储正在执行的请求数running,请求队列queue,所有的请求结果result。
js
class PromisePool {
constructor(concurrency) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
this.results = [];
}
}
2.定义类方法
- 首先我们需要将请求传入实例对象中,则需要定义add方法,返回一个promise对象,通过.then()方法接收接口返回值;
- 其次,将请求传入后需要控制请求的执行,则需要定义run方法,也返回一个promise对象,核心逻辑是根据running和concurrensy判断当前请求需要执行或进入queue队列;
- 如果当前running < concurrency,则需要从队列中取请求执行,这里需要定义next()方法;
js
class PromisePool {
constructor(concurrency) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
this.results = [];
this.taskCallbacks = [];
}
add(...tasks) {
const taskPromises = tasks.map(task => this.run(task))
return Promise.all(taskPromises);
}
run(task) {
return new Promise((resolve, reject) => {
const warppedTask = async () => {
try {
const result = await task();
this.results.push(result);
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.next();
}
}
if (this.running < this.concurrency) {
this.running++;
warppedTask();
} else {
this.queue.push(warppedTask);
}
})
}
next() {
if (this.queue.length > 0 && this.running < this.concurrency) {
const task = this.queue.shift();
this.running++;
task();
}
}
}
3.使用
js
const task = [
() => new Promise(resolve => {
setTimeout(() => {
resolve('task1');
}, 1000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task2');
}, 2000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task3');
}, 3000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task4');
}, 4000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task5');
}, 1000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task6');
}, 4000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task7');
}, 1000)
}),
]
pool.add(task[0]).then(result => {
console.log('任务完成:', result);
});
pool.add(task[1]).then(result => {
console.log('任务完成:', result);
});
pool.add(task[2]).then(result => {
console.log('任务完成:', result);
});
pool.add(task[3]).then(result => {
console.log('任务完成:', result);
});
pool.add(task[4]).then(result => {
console.log('任务完成:', result);
});
pool.add(task[5]).then(result => {
console.log('任务完成:', result);
});
pool.add(() => new Promise(resolve => {
setTimeout(() => {
resolve('单独任务');
}, 1000)
})).then(result => {
console.log('任务4完成:', result);
});
输出:

4.传入数组,监听返回
这里通过注册任务完成的回调函数实现,在每个接口resolve时调用函数
js
class PromisePool {
constructor(concurrency) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
this.results = [];
this.taskCallbacks = [];
}
onTaskDone(callback) {
this.taskCallbacks.push(callback);
return this;
}
add(...tasks) {
const taskPromises = tasks.map(task => this.run(task))
return Promise.all(taskPromises);
}
run(task) {
return new Promise((resolve, reject) => {
const warppedTask = async () => {
try {
const result = await task();
this.results.push(result);
this.taskCallbacks.forEach(cb => cb(result));
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.next();
}
}
if (this.running < this.concurrency) {
this.running++;
warppedTask();
} else {
this.queue.push(warppedTask);
}
})
}
next() {
if (this.queue.length > 0 && this.running < this.concurrency) {
const task = this.queue.shift();
this.running++;
task();
}
}
}
let pool = new PromisePool(3);
const task = [
() => new Promise(resolve => {
setTimeout(() => {
resolve('task1');
}, 1000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task2');
}, 2000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task3');
}, 3000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task4');
}, 4000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task5');
}, 1000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task6');
}, 4000)
}),
() => new Promise(resolve => {
setTimeout(() => {
resolve('task7');
}, 1000)
}),
]
调用函数
js
// 注册任务完成回调(实时获取结果)
pool.onTaskDone(result => {
console.log('实时结果:', result);
});
pool.add(...task).then(result => {
console.log('任务完成:', result);
});
结果
end~~~