前言
公司的素材管理模块,客户下载文件1500个,在生产环境中,下载报错# ERR_INSUFFICIENT_RESOURCES,查找原因,是使用for循环创建了1500个获取资源的请求,超出了浏览器发起请求最大资源(1350个左右,自己试验总结),于是产生了队列上传的想法,同时最多有6个上传。
代码搬运
const dataRequest = [
{
"file_name": "/免洗洗手液 松木50ml-69029424/主图/69029424-3.jpg",
"file_url": "https://mcms-manon.oss-cn-shanghai.aliyuncs.com/prod/700/image/materials/202204/41/rc-upload-1650774625197-552.jpg"
},
{
"file_name": "/免洗洗手液 松木50ml-69029424/主图/69029424-2.jpg",
"file_url": "https://mcms-manon.oss-cn-shanghai.aliyuncs.com/prod/700/image/materials/202204/41/rc-upload-1650774625197-551.jpg"
},
{
"file_name": "/免洗洗手液 松木50ml-69029424/主图/69029424-1.jpg",
"file_url": "https://mcms-manon.oss-cn-shanghai.aliyuncs.com/prod/700/image/materials/202204/41/rc-upload-1650774625197-550.jpg"
},
{
"file_name": "/免洗洗手液 松木50ml-69029424/详情页/69029424-23.jpg",
"file_url": "https://mcms-manon.oss-cn-shanghai.aliyuncs.com/prod/700/image/materials/202204/41/rc-upload-1650774625197-573.jpg"
},
]
let _that = this
this.sendRequest(dataRequest,6,_that,zip,()=>{
zip.generateAsync({ type: 'blob',compression: "DEFLATE",
compressionOptions: {
level: 9} // 压缩等级1~9 1压缩速度最快,9最优压缩方式
}).then((content) => {
this.setState({downloadspinning:false,successNum:0,totalFileNum:0,})
// 生成二进制流,利用file-saver保存文件
saveAs(content, `${批量下载}.zip`);
})
})
//请求文件资源
getFile_v2 =(url,index,item)=>{
return new Promise((resolve, reject) => {
axios({
method: 'get',
url:url + `?` +Date.now(),
responseType: 'blob',
}).then((data) => {
resolve(data.data);
this.setState({successNum:this.state.successNum+1})
}).catch((error) => {
reject(error.toString());
});
});
}
sendRequest = (urls, max, _that, zip, callbackFunc)=> {
// console.log(urls);
const REQUEST_MAX = max;
const TOTAL_REQUESTS_NUM = urls.length;
const blockQueue = []; // 等待排队的那个队列
let currentReqNumber = 0; // 现在请求的数量是
let numberOfRequestsDone = 0; // 已经请求完毕的数量是
const results = new Array(TOTAL_REQUESTS_NUM).fill(false); // 所有请求的返回结果,先初始化上
async function init() {
// console.log('========init');
for (let i = 0; i < urls.length; i++) {
request(i, urls[i], _that);
}
}
async function request(index, reqUrl,_that) {
// console.log('========request');
// 这个index传过来就是为了对应好哪个请求,
// 放在对应的results数组对应位置上的,保持顺序
if (currentReqNumber >= REQUEST_MAX) {
await new Promise((resolve) => blockQueue.push(resolve)); // 阻塞队列增加一个 Pending 状态的 Promise,
// 进里面排队去吧,不放你出来,不resolve你,你就别想进行下面的请求
}
reqHandler(index, reqUrl, _that); // {4}
}
async function reqHandler(index, reqUrl,_that) {
// console.log('=====reqHandler',_that);
currentReqNumber++; // {5}
try {
const res = await _that.getFile_v2(reqUrl.file_url);
results[index] = res;
zip.file(reqUrl.file_name, res, { binary: true });
} catch (err) {
results[index] = err;
} finally {
currentReqNumber--;
numberOfRequestsDone++;
if (blockQueue.length) {
// 每完成一个就从阻塞队列里剔除一个
blockQueue[0](); // 将最先进入阻塞队列的 Promise 从 Pending 变为 Fulfilled,
// 也就是执行resolve函数了,后面不就能继续进行了嘛
blockQueue.shift();
}
if (numberOfRequestsDone === TOTAL_REQUESTS_NUM) {
callbackFunc(results);
}
}
}
init();
}
参考
前端面试题:实现批量请求数据,并控制请求并发数量,最后所有请求结束之后,执行callback回调函数_擦拉嘿的博客-CSDN博客_实现一个批量请求函数, 能够限制并发量?