5分钟搞定Promise控制并发


起因 项目需要做一个上传功能,每次上传20个视频,不处理直接传的话会有一个阻塞问题。
因为一个网页最多同个域名只能有6个tcp连接。不控制并发同时传6个,用户后续的所有调其他接口的操作都会被挂起来。网络不好的情况下更是灾难,所以需要控制并发,一次最多只传3个。
正好又有这种类型的面试题,写个demo讲下原理。
后端代码 后端需要后整基本的返回,随机延迟,随机错误,能跨域

const http = require('http') http.createServer((req,res)=>{const delay = parseInt(Math.random()*5000) console.log(delay); setTimeout(()=>{ const returnerror = Math.random()>0.8 // if(returnerror){ //res.writeHead(500,{ //// 'Content-Type': 'text/plain', //'Access-Control-Allow-Origin':'*', //'Access-Control-Allow-Headers':'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild', //'Access-Control-Allow-Methods':'GET', //}).end('error,from '+req.url+' after '+delay+'ms') // }else{ res.writeHead(200,{ // 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin':'*', 'Access-Control-Allow-Headers':'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild', 'Access-Control-Allow-Methods':'GET', }).end('OK,from '+req.url+' after '+delay+'ms') // }},delay) }).listen(3000,()=>{ console.log('服务启动在3000!'); })

前端代码 html主要为了动画的一个展示,就不细说了。
js分为两部分,一部分控制dom渲染,这个也不细说了,第二部分就是并发控制器
input数组里面是请求地址
5分钟搞定Promise控制并发
文章图片

基础版
并发控制主要是两个函数和一个promise队列
  • 一个负责不断的递归往队列里面加promise。
  • 另外一个负责生产promise,处理异步请求逻辑
function handleFetchQueue(input, max) { const requestsQueue = []; // 请求队列 addReactive(requestsQueue) //对requestsQueue添加响应式 let i = 0; const req = (i)=>{//产生一个promise请求 成功则删除队里中promise 再添加一个请求 returnfetch(input[i]).then(res=>res.text()).then(res=>{ addEl(res) //结果渲染页面列表 const index = requestsQueue.findIndex(item=>item===req) requestsQueue.splice(index,1) checkAddReq() }) } const checkAddReq = ()=>{ if(i>=input.length) return // 请求数不能越界 if(requestsQueue.length+1 <= max) { // 并发不能越界 setTimeout(()=>{ //加延迟为了提高动画效果,实际不需要 requestsQueue.push(req(i++)) checkAddReq() },50)} } checkAddReq(); } handleFetchQueue(input,3)

处理异常
需要考虑的问题是异常了怎么办。
异常对于并发控制也就是计数原理应该没有区别,只是需要额外再promise生成这里添加下业务逻辑即可。
我们把后端代码随机错误的注释打开
然后前端核心逻辑改一下
const req = (i)=>{ returnfetch(input[i]).then(async(res)=>{ if(res.status===500){ //这里异步改一下,得让走catch const text = await res.text() throw new Error(text); }else{ return res.text() } }).then(res=>addEl(res),error=>addEl(error,true)) .finally(()=>{ //无论成功失败并发逻辑一样,只是then中业务逻辑不同 const index = requestsQueue.findIndex(item=>item===req) requestsQueue.splice(index,1) checkAddReq() }) }

总结 完整地址 https://github.com/fyy92/code...
  • index.html 不考虑异步
  • index1.html 考虑异常
  • serve.js 后端代码
【5分钟搞定Promise控制并发】总结一下
  • 并发控制关键在两个函数,一个控制生成业务Promise,一个迭代控制并发队列添加业务Promise。
  • 对于异常,需要保证并发逻辑一样,不同的是业务逻辑的处理。

    推荐阅读