Chrome 浏览器最多并发6个请求。一般情况下,我们都会设置并发数为 3。
并发请求控制主要有两种区别:假设并发数为 3
- 三个请求为一组进行并发,这三个请求全部完成了,再进行下一组。
- 在第一种方式的基础上加上滑动补位,第一组三个请求,当其中一个请求完成,后续第4个请求,迅速补上发起请求。
这两种方式,第一种压根不是并发请求,准确说应该是并发发起请求。第二种有了滑动补位,才能说是一直以最大并发数在进行请求流程。
实现并发控制的核心:await Promise,将异步变同步。
/**
* 并发请求控制
* @param {Function[]}requestArr 请求函数组成的数组
* @param {number}limit 并发数量,默认为 3
* @returns {Promise<any>[]} 每个请求的 promise 组成的数据
*/
export async function controlConcurrency(
requestArr: ((...args: any[]) => Promise<any>)[],
limit: number = 3
): Promise<any>[] {
// 如果并发数小于等于0,抛出错误
if (limit <= 0) throw new Error("并发限制必须大于0");
const results: Promise<any>[] = []; // 结果数组
const running: Promise<any>[] = []; // 并发数组
// 遍历请求数组
for (const request of requestArr) {
// 调用请求函数,返回一个Promise
const promise = request();
// 将Promise添加到结果数组
results.push(promise);
// 将Promise添加到并发数组
running.push(promise);
// 如果并发数组的长度大于限制数,则等待running数组中最先完成的promise
if (running.length >= limit) {
await Promise.race(running);
}
// 每次Promise完成,从并发数组中移除
promise.finally(() => {
const index = running.indexOf(promise);
if (index !== -1) running.splice(index, 1);
});
}
// 返回所有Promise的结果
return results;
}
测试代码:
const requestsArr = []
for (let index = 0; index < 10; index++) {
requestsArr[index] = () => fetch('http://localhost/user')
}
controlConcurrency(requestsArr, 2).forEach(item => {
item.then(response => {
response.json().then(res => {
console.log(res);
})
})
.catch(err => {
console.log(err);
})
})
测试接口:
const express = require('express')
const app = new express()
// 跨域
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '*');
res.header('Content-Type', 'application/json;charset=utf-8');
next();
});
function getRandom() {
return Math.floor(Math.random() * 10) + 1
}
app.get('/user', (req, res) => {
const d = getRandom()
// 随机延迟响应
setTimeout(() => {
res.json({time: d})
}, d * 500)
})
app.listen(80, ()=> {
console.log("express server running at http://127.0.0.1:80")
})