JavaScript/TypeScript 实现并发请求控制的示例代码
场景
假设有10个请求,但是最大的并发数目是5个,并且要求拿到请求结果,这样就是一个简单的并发请求控制
模拟
利用setTimeout实行简单模仿一个请求
letstartTime=Date.now(); consttimeout=(timeout:number,ret:number)=>{ return(idx?:any)=> newPromise((resolve)=>{ setTimeout(()=>{ constcompare=Date.now()-startTime; console.log(`At${Math.floor(compare/100)}00return`,ret); resolve(idx); },timeout); }); }; consttimeout1=timeout(1000,1); consttimeout2=timeout(300,2); consttimeout3=timeout(400,3); consttimeout4=timeout(500,4); consttimeout5=timeout(200,5);
通过这样来模拟请求,本质就是Promise
没有并发控制的时候
construn=async()=>{ startTime=Date.now(); awaitPromise.all([ timeout1(), timeout2(), timeout3(), timeout4(), timeout5(), ]); }; run(); At200return5 At300return2 At400return3 At500return4 At1000return1
可以看到输出是52341,按timeout的时间输出了
并发条件
假设同时间最大并发数目是2,创建一个类
classConcurrent{ privatemaxConcurrent:number=2; constructor(count:number=2){ this.maxConcurrent=count; } }
第一种并发控制
想一下,按最大并发数拆分Promise数组,如果有Promise被fulfilled的时候,就移除掉,然后把pending状态的Promise,加进来。Promise.race可以帮我们满足这个需求
classConcurrent{ privatemaxConcurrent:number=2; constructor(count:number=2){ this.maxConcurrent=count; } publicasyncuseRace(fns:Function[]){ construning:any[]=[]; //按并发数,把Promise加进去 //Promise会回调一个索引,方便我们知道哪个Promise已经resolve了 for(leti=0;i{ if(fns.length){ constidx=awaitPromise.race (runing); constnextFn=fns.shift()!; //移除已经完成的Promise,把新的进去 runing.splice(idx,1,nextFn(idx)); handle(); }else{ //如果数组已经被清空了,表面已经没有需要执行的Promise了,可以改成Promise.all awaitPromise.all(runing); } }; handle(); } } construn=async()=>{ constconcurrent=newConcurrent(); startTime=Date.now(); awaitconcurrent.useRace([timeout1,timeout2,timeout3,timeout4,timeout5]); }; At300return2 At700return3 At1000return1 At1200return5 At1200return4
可以看到输出已经变了,为什么会这样呢,分析一下,最大并发数2
//首先执行的是12
1需要1000MS才执行完
2需要300MS2执行完,时间线变成300移除2加入3开始执行3
3需要400MS执行完时间变成700移除3加入4开始执行4
4需要500MS
时间线来到1000MS,1执行完移除1加入5开始执行5
时间线来到1200MS,4和5刚好同时执行完
第二种方案
可以利用await的机制,其实也是一个小技巧
await表达式会暂停当前asyncfunction的执行,等待Promise处理完成。若Promise正常处理(fulfilled),其回调的resolve函数参数作为await表达式的值,继续执行asyncfunction。
如果当前的并发数已经超过最大的并发数目了,可以设置一个新的Promise,并且await,等待其他的请求完成的时候,resolve,移除等待,所以需要新增两个状态,当前的并发数目,还有用来存储resolve这个回调函数的数组
classConcurrent{ privatemaxConcurrent:number=2; privatelist:Function[]=[]; privatecurrentCount:number=0; constructor(count:number=2){ this.maxConcurrent=count; } publicasyncadd(fn:Function){ this.currentCount+=1; //如果最大已经超过最大并发数 if(this.currentCount>this.maxConcurrent){ //wait是一个Promise,只要调用resolve就会变成fulfilled状态 constwait=newPromise((resolve)=>{ this.list.push(resolve); }); //在没有调用resolve的时候,这里会一直阻塞 awaitwait; } //执行函数 awaitfn(); this.currentCount-=1; if(this.list.length){ //把resolve拿出来,调用,这样wait就完成了,可以往下面执行了 constresolveHandler=this.list.shift()!; resolveHandler(); } } } construn=async()=>{ constconcurrent=newConcurrent(); startTime=Date.now(); concurrent.add(timeout1); concurrent.add(timeout2); concurrent.add(timeout3); concurrent.add(timeout4); concurrent.add(timeout5); }; run(); At300return2 At700return3 At1000return1 At1200return5 At1200return4
总结
这两种方式都可以实现并发控制,只不过实现的方式不太一样,主要都是靠Promise实现,另外实现方式里面没有考虑异常的情况,这个可以自己加上
到此这篇关于JavaScript/TypeScript实现并发请求控制的示例代码的文章就介绍到这了,更多相关JavaScript并发请求控制内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。