如何实现并发请求数量控制?

前言
本文为转载文章,原文地址:关于前端:如何实现并发请求数量控制?
对文章作者表示感谢。
文章代码实现部分根据理解做了部分修改,整体效果无差异。
场景
假设有这么一个场景:现在有20
个异步请求需要发送,但是由于某些原因,要求我们必须将同一时刻的并发请求数量控制在3
个以内,并且还要尽可能快速的拿到响应结果。其实这个场景在一些大厂的面试题中也有过提及,如下:
1 2 3 4
| 实现一个并发请求函数 concurrencyRequest(urls, maxNum),要求如下: • 要求最大并发数 maxNum • 每当有一个请求返回,就留下一个空位,可以增加新的请求 • 所有请求完成后,结果按照 urls 里面的顺序依次打出(发送请求的函数可以直接使用fetch即可)
|
设计思路
首先来看将上面的文字转化为图之后的效果:

这样就直观的看到,有一个最大并发数maxNum
,20
个异步请求的urls
集合和并发返回之后的results
集合。
下面就开始演示这个思路是如何开始的,如下:

首先按照每次只能并发3
个请求的要求,这里就对应A、B、C
,当其中有一个请求完之后就会再从urls
里面再取出一个进行请求,这样依次类推,直到urls
里面的20
个请求都执行完才终止请求。

主要思路就是上面所述,但是在开发时我们要考虑一些特殊情况,如下:
urls
的长度为0
时,results
就没有值,此时应该返回空数组
maxNum
大于urls
的长度时,应该取的是urls
的长度,否则则是取maxNum
- 需要定义一个
count
计数器来判断是否已全部请求完成
- 因为没有考虑请求是否请求成功,所以请求成功或报错都应把结果保存在
results
集合中
results
中的顺序需和urls
中的保持一致
开发
具体代码如下:
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 31 32 33 34 35 36 37
| const concurrencyRequest = (urls, maxNum) => { return new Promise((resolve) => { if (urls.length === 0) { resolve([]); return; } const results = []; let index = 0; let count = 0;
async function request () { if(index === urls.length) return; const i = index; const url = urls[index]; index++; try { const res = await fetch(url); const json = await res.json(); results[i] = json; } catch (e) { results[i] = e; } finally { count++; if(count === urls.length) { console.log('Done'); resolve(results); } request(); } }
const times = Math.min(maxNum, urls.length); for(let i = 0; i < times; i++) { request(); } }) }
|
测试
在上面代码下添加如下代码:
1 2 3 4 5 6 7 8 9 10 11
| (async () => { const urls = []; const maxNum = 3; for (let i = 1; i <= 20; i++) { urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`); } console.time('request'); const res = await concurrencyRequest(urls, maxNum); console.timeEnd('request'); console.log(res); })()
|
结果
