问题:我们在前端请求中有时会碰到大量的并发请求下载,promise.all可以做到并发请求,但是没有对最大的并发数量做控制。
解决方案:
module.exports = class myAsyncPoll {
list = []; //任务池
maxLimit = 50; //任务池最大同时执行任务队列的数量
workingNum = 0; //任务池中启动队列的数量
//设置最大执行数量
setMaxLimit(num) {
this.maxLimit = num;
}
//往队列池中添加任务
add(promiseCreater) {
this.list.push(promiseCreater);
}
//开始启动任务池中的任务队列
start() {
for (let i = 0; i < this.maxLimit; i++) {
this.doNext();
}
}
//任务队列的自动执行(空闲自动调用下一个)
doNext() {
if (this.list.length && this.workingNum <= this.maxLimit) {
this.workingNum++;
//this.list.shift()() 找到数组中第一个并调用异步任务
//.then()中执行下一个,并修改工作的任务数量-1
this.list
.shift()()
.then(() => {
this.workingNum--;
this.doNext();
});
}
}
};
思路:我们定义一个任务池,通过add方法往任务池中添加(promise对象),通过doNext()方法,做到任务池中的每个任务队列都能执行完每个任务以后,将空闲的任务自动补充进队列中。通过start()开启多条,setMaxLimit()方法设置的最大任务队列。
举一个栗子:(productsInfo是保存了图片下载链接的数组)
const asyncPool = new myAsyncPoll();
asyncPool.setMaxLimit(maxDownloadNUM); //设置最大同时并发任务量
productsInfo.map(async (item) => {
asyncPool.add(() => {
return new Promise((resolve) => {
downloadFile(
item.imgUrl,
`./public/${currentPage}`,
`${item.title.replace(/\/|\\|\*|"|'/g, "-")}.png`
);
});
});
});
asyncPool.start();
downloadFile:
const axios = require("axios");
const fs = require("fs");
const path = require("path");
module.exports = async function downloadFile(url, filepath, name) {
try {
if (!fs.existsSync(filepath)) {
fs.mkdirSync(filepath);
}
const mypath = path.resolve(filepath, name);
const writer = fs.createWriteStream(mypath);
const response = await axios({
url,
method: "GET",
responseType: "stream",
});
response.data.pipe(writer);
} catch (error) {
console.log(error);
}
};