一、业务场景
某一天,产品小姐姐让前端老王实现一个批量更新列表数据的需求。老王窃喜,小儿科,后端提供一个更新的接口不就完事儿了。不料,一直配合默契的后端那个哥们儿,刚刚删库跑路了,所以,就把这个接口开发的任务交给了一个新来的开发小弟弟。这个小弟弟比较实诚,三下五除二的就搞定了。然后找到老王说,“王哥哈,这个更新列表的接口写好了,你需要多次调用这个接口。”
“ what?调用一次不行么?” “不行,因为列表批量更新数据比较大,如果其中一个更新失败,会导致这一批的更新失败,客户会投诉咱们滴,所以需要分别更新哈。” “ md,有点儿道理哈。” 突然,产品小姐姐,来了一句,“要尽可能高效的完成批量更新数据呀!,咱们的客户属于小白那种!” 然后,隔壁老王就屁颠屁颠的开始疯狂撸码中。
二、归纳转化
老王苦思冥想,吹了吹掉在桌子上的2根头发,然后喃喃道,原来如此! N个请求,最大并发请求个数M(M <= N),要求尽可能多的每刻执行M个请求
三、实现原理
- 创建一个待请求队列池(N),创建一个正在请求队列(M)
- 正在请求队列中任意一个请求完成后,通过notify函数发布通知
- 把请求结果存储在response中
- 已发送请求个数加一
- 如果已发送请求个数等于待请求队列总数,则所有请求发送完毕
- 外部调用者通过callback函数,拿到最终的结果集合
四、代码解析
/**
* 并发请求
* 需求:n个请求,最大并发请求个数m(m <= n),要求尽可能多的每刻执行m个请求。
*/
import { getPluginVersionList } from '../axios/api';
class RequestService {
/**
* 待请求队列池【N】
*/
requestQueue = [];
/**
* 最大并发请求个数【M】
*/
limit = 0;
/**
* 并发请求的结果集合
*/
response = [];
/**
* 最大请求总数
*/
maxRequestCount = 0;
/**
* 已发送的请求个数
*/
sentRequestCount = 0;
/**
* 外部调用者回调函数
*/
callback = null;
constructor(limit, list) {
this.limit = limit;
this.requestQueue = this.getRequestQueue(list);
this.maxRequestCount = this.requestQueue.length;
}
/**
*批量发送请求
* @param {Function} callback
*/
sendRequest(callback) {
this.callback = callback;
// 正在请求队列
for (let i = 0; i < this.limit; i++) {
const request = this.requestQueue.shift();
request(this.notify.bind(this));
}
}
/** private method */
addRequest() {
const request = this.requestQueue.shift();
if (request) {
request(this.notify.bind(this));
}
}
/** private method */
notify(value) {
this.sentRequestCount++;
this.response.push(value);
this.addRequest();
if (this.sentRequestCount === this.maxRequestCount) {
this.callback(this.response);
}
}
/**
* private method
* 请求接口封装
* @param {} param `请求接口参数`
* @returns Function
*/
request(param) {
return function request(notify) {
getPluginVersionList({ id: param }).then(res => {
// 通知外部请求接口成功
notify(res);
});
}
}
/**
* private method
* 待请求队列池
* @param {Array} list `选中的列表数据`
* @returns
*/
getRequestQueue(list) {
return list.map(item => this.request(item));
}
}
// 使用举例:
// 假如选中表格中的列表数据250条,任意时刻最大并发请求个数为13;
// 选中的列表数据
const selectedList = Array.from({ length: 250 }, (v, k) => k + 1);
const limit = 13;
const requestService = new RequestService(limit, selectedList);
requestService.sendRequest(function callback(res) {
console.log(res);
});