前言 📝
在前端进行并发请求的时候,前端浏览器为了减轻服务器的压力,限制同一域名下并发请求的最大数量是6~8个(每个浏览器的最大并发数量不一致)。既然浏览器帮助我们控制了最大并发量,那为什么还要手动控制并发呢?原因很简单,因为面试官会问。其实还有一点就是,浏览器默认的等待机制是全局的,无法做到更细粒度的控制。我们手写控制并发的情况下,自己可以实现不同的排队策略、错误处理策略、超时处理策略、控制最大并发数量等。
如下所示,定义一个 result
用来缓存请求队列返回的结果,定义一个参数 index
记录下一次请求的索引。然后我们按照并发量去循环发送网络请求。在循环请求的时候,finally
中判断是否继续发送请求还是终止请求返回所有结果。
注意:result
存储的是返回结果,但是并发多个请求返回的顺序并不一致,所以在fetchApi
函数内定了i
,来记录当前网络请求的索引。用于将网络请求的返回结果存储在对应的位置。
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 38 39 40 41 42 43 44 45
| <script> const requestQueue = (urls = [], maxNum = 6) => { return new Promise((resolve, reject) => { if(!urls.length) { resolve([]) return }
const result = [] let index = 0
async function fetchApi() { const i = index const url = urls[i] index++
try { const resp = await fetch(url) const res = await resp.json() result[i] = res } catch(err) { result[i] = err } finally { if(result.length === urls.length) { resolve(result) return } if(index < urls.length) { fetchApi() } } }
const count = Math.min(maxNum, urls.length) for(let i = 0; i < count; i++) { fetchApi() } }) }
const urls = new Array(8).fill('http://127.0.0.1:3000') requestQueue(urls, 4).then(res => console.log(res)) </script>
|
我们简单用node写一个服务端的代码,测试一下我们的函数有没有问题:
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 38 39 40
| const http = require('http'); const url = require('url'); const hostname = '127.0.0.1'; const port = 3000;
const server = http.createServer((req, res) => { const parsedUrl = url.parse(req.url, true); const pathname = parsedUrl.pathname; const method = req.method;
res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*');
if (method === 'GET' && pathname === '/') { res.statusCode = 200; console.log('Have connect: ' + parsedUrl.query.index); setTimeout(() => { res.end(JSON.stringify({ message: 'Hello World!' })); }, 6000) } else if (method === 'POST' && pathname === '/data') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { const data = JSON.parse(body); res.statusCode = 200; res.end(JSON.stringify({ message: `You sent: ${JSON.stringify(data)}` })); }); } else { res.statusCode = 404; res.end(JSON.stringify({ message: 'Not Found' })); } });
server.listen(port, hostname, () => { console.log(`Server is running at http://${hostname}:${port}/`); });
|
我这里并发数量改成6,接口换成100个试一下:
1 2
| const urls = new Array(100).fill('http://127.0.0.1:3000') requestQueue(urls, 6).then(res => console.log(res))
|

我们可以看到和我们的预期一样,一次发送6个请求。正好发送了一百个网络请求,最后将返回值按照发送请求的顺序对应的放到数组里面全部返回。

