实现一个批量请求函数 multiRequest(urls, maxNum),要求如下:
- 要求最大并发数 maxNum
- 每当有一个请求返回,就留下一个空位,可以增加新的请求
- 所有请求完成后,结果按照 urls 里面的顺序依次打出
// 线程池思想, 最大线程数maxNum个
function request(url, callback) {
console.log(url, "开始请求啦")
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(url+"成功啦");
}, Math.random() * 2000);
})
}
function multi(maxNum = 5) {
let pool = [];
let wait = [];
let ret = [];
let count = 0;
let emptyCallback = null;
function task(url, s, f) {
this.key = count;
this.url = url;
count++;
this.ret = undefined;
this.status = "pending";
this.error = undefined;
this.run = () => {
this.status = "running";
new Promise((resolve, reject) => {
request(url)
.then(res => {
this.status = "success";
this.ret = res;
s();
}).catch(err => {
this.status = "error";
this.error = err;
f();
})
})
}
}
this.setCallback = (callback)=>{
emptyCallback = callback;
};
this.add = (url) => {
const t = new task(url, ()=>{
ret.push(t)
finish(t);
}, ()=>{
finish(t);
})
wait.push(t);
check(); // 每次添加触发检查
}
function finish(task) {
let index = -1;
for (let i in pool) {
if (task.key === pool[i].key) {
index = i;
break;
}
}
if (index >= 0) {
pool.splice(index, 1);
console.log(task.url, "结束啦");
check(); // 每当有任务结束, 触发检查
}
}
function check() {
// 检查wait, 看看有没有等待任务, 检查pool, 看是否有空位
if (wait.length > 0 && pool.length < maxNum) {
// 有空位, 补位
pool.push(wait.shift())
}
// 消费
for (let task of pool) {
if (task.status === "pending") {
task.run();
}
}
if (pool.length === 0) {
// 触发任务清空回调
console.log("任务清空")
const r = ret.sort((x, y) => x.key - y.key)
console.log(r)
emptyCallback && emptyCallback(r);
ret = [];
count = 0;
}
}
}
function multiRequest(urls, maxNum) {
const m = new multi(maxNum);
for (let url of urls) {
m.add(url)
}
m.setCallback((rets)=>{
for (let ret of rets) {
console.log(ret);
}
})
}
multiRequest(["000",'111','222','333'], 2);