很久以前发了一篇文章,文章里主要探讨了这样一个问题,页面中需要发送多次ajax请求,如何确保所有数据返回后才对数据一起进行操作,文章名称为:
就在前不久这个并发的问题升级了,问题变成了这样子的,比如某个页面需要请求资源,需要发送100次请求,100次不能同时同时发送,要做到并发控制,,要求你的页面或程序最大并发数只能是5,请求数大于5时只能等待,请求数小于5时从100中拿出一条来发送。
这段代码或者这段程序如何完成呢?
我们用一张图来表示一下这个场景,100个人去食堂打饭,只有5个窗口,如何才能做到效率最高呢?
第一种情况人员分成五组,分别排队,每队二十人。如图:
这张图初看好像没有问题,但是仔细思考下,假如1、2、3、4窗口的人很快就完成了,5的队伍中有个2B有选择恐惧症加拖延症,就会出现如下所示的情况:
1,2,3,4空闲了。所以不能这样做,抛弃这种设置,代码肯定不能按照这种形式来实现。
第二种设计如图:
仔细看看这种设计,乍一看好像队伍变长了,但是处理的效率大大提高了,并且窗口也没有空闲,这样就算碰见2B也不用担心了,因为这个2B不能阻止所有窗口。
那基于这样的设计,代码该如何实现呢?
这里我们用定时器setTimeout来模拟异步请求,模拟代码如下:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30];
var l = arr.length
// 限制的请求数量
var limit = 0;
// 计数器
var count = 0;
// 完成的请求数量
var sum = 0;
// 请求结果返回这个数组的每一项。
var result=[];
// 定义一个递归函数,函数执行时,根据计数器先判断当前正在请求的数量;
// 请求数量小于5并且请求url数组的长度大于0,那么就发送请求,否则啥也不干
// 满足条件的话,计数器count自增1,并且从arr中pop出一条url,然后进行异步操作
// 这里用定时器模拟异步操作,异步操作完成后,计数器自减1并处理结果,sum总的计数器加1
// 递归调用自己
var asyncreq = function(){
if(count<5&&arr.length>0){
count++;
console.log("现在并发数是",count);
let ele = arr.pop();
setTimeout(()=>{
count--;
console.log("现在并发数是",count);
asyncreq()
sum++
result.push(ele*10);
if(sum==l){
console.log(result.length);
}
},5000*Math.random()+3000)
}
}
// 瞬间开启5个请求
for (let i = 0; i < 5; i++) {
asyncreq();
}
执行结果:
时刻保持5的并发数直至结束。
回顾一下上面的代码,主要应用了递归函数,每个函数的内部首先判断当前请求数的数量,和请求url的剩余数量,当请求数小于5,请求url剩余量大于0,满足条件后,执行异步操作,pop出一条url,异步造作完成后,计数器自减,总的请求数量自增,如果总的请求数量与初始url数量一致,处理总的结果。
以上便是对大量异步请求控制并发数的一种操作方法,当然还有其他方法,欢迎大家在留言区探讨。