在开发中, 我们经常会遇到多个请求同时进行的需求,请求不多时,我们可以直接使用
Promise.all()
来进行并发请求,一般也不会有问题,但是这样也会有弊端,比如:
- 其中一个请求比较慢,那么所有的请求就需要等待。
- 一个请求出错,那么就代表
Promise.all()
失败,不利于后续逻辑处理。- http1.1一个域名只能同时有6个请求,当同时并发请求比较多时,多余的请求,需要等待别的请求完成,而
Promise.all()
又需要等所有请求完成,所以会更慢。- 请求数量过多,页面上的功能又需要逐步渲染显示,而不是等待所有接口完成。
所以,基于上面这些问题我们就需要控制请求的并发,以下就是并发控制的基本代码,同时为了方便再一个页面中,会有多个功能模块中需要并发控制,在RequestQueue
类外面多封装了一层。
// 并发控制
class RequestQueue {
/**
* @param {number} concurrence
*/
constructor(concurrence = 4) {
// 默认设置并发数量
this.concurrence = concurrence < 4 ? 4 : concurrence;
// 任务队列
this.queue = [];
// 正在执行的任务数
this.runing = 0;
// 是否暂停
this.isPause = false;
}
/**
* 加入请求任务
* @param {funtion} fn 请求任务
* @returns {void}
*/
join(fn) {
if (typeof fn !== 'function') {
console.log('请添加一个函数!!!');
return;
}
if (this.isPause || this.runing >= this.concurrence) {
this.queue.push(fn);
return;
}
this.excute(fn)
}
/**
* 执行函数
* @param {function} fn fn
* @returns {void}
*/
async excute(fn) {
// 正在执行的数量增加
this.runing += 1;
try {
await fn();
} catch (error) {
console.log('requestQueue执行请求报错~~~');
} finally {
this.runing -= 1;
this.next();
}
}
/**
* 下一个
* @returns {void}
*/
next() {
if (this.isPause || this.runing >= this.concurrence || !this.queue.length) {
return;
}
const fn = this.queue.shift();
this.excute(fn);
}
/**
* 暂停
* @returns {void}
*/
pause() {
this.isPause = true;
}
/**
* 恢复
* @returns {void}
*/
resume() {
this.isPause = false;
this.next();
}
/**
* 清理
* @returns {void}
*/
clear() {
this.isPause = false;
this.queue = [];
this.runing = 0;
}
}
const requestQueueMap = new Map();
/**
* 不同命名空间并发请求队列
*/
class NamespaceRequestQueue {
/**
* @param {string} name 命名空间
* @param {number} concurrence 并发量
*/
constructor(name, concurrence) {
this.namespace = name;
let rq = requestQueueMap.get(name);
if (!rq) {
rq = new RequestQueue(concurrence);
requestQueueMap.set(name, rq);
}
// 当前的请求队列
this.requestQueue = rq;
}
join(fn) {
this.requestQueue.join(fn);
}
next() {
this.requestQueue.next();
}
pause() {
this.requestQueue.pause();
}
resume() {
this.requestQueue.resume();
}
clear() {
this.requestQueue.clear()
}
/**
* 销毁,清空所有命名空间的并发控制
*/
destroy() {
this.requestQueue = null;
this.namespace = '';
for (const instance of requestQueueMap.values()) {
instance.clear();
}
requestQueueMap.clear();
}
}
export {
RequestQueue,
}
export default NamespaceRequestQueue;
主要有两个类RequestQueue
和NamespaceRequestQueue
,其中主要功能为RequestQueue
类,NamespaceRequestQueue
可以通过命名空间,控制不同的并发功能模块。