理解: 先举个例子,假设我们去银行办业务。有两个柜台,这就是最大并发数。当我们去的时候,先抽号排队,然后再去柜台。
情况一:
柜台没人,这时候第一个人可以直接去,也就是当柜台没有人,直接去。
第二种情况:柜台满了,只能排队
第三种情况
柜台有人离开,那么后面的接着上。
这里的柜台,就是最大并发数,同时只能办理两个人,排队就是一个队列,当有空位出现,先进的先出。
当所有人办理结束,那么整体情况也结束。
实现思路: 首先定义maxTask:最大并发数,tasks:队列,runingCount:正在请求个数 add方法:当有请求过来,就进入排队,然后看看要不要去柜台办理,所以用run方法 run方法:
- 首先判断柜台有没有位置:this.runingCount < this.maxTask,如果有位置,直接排队的人出一个去柜台办理,如果没位置,就不处理
- 判断排队还有没有人:this.tasks.length !== 0 ,没人就不处理 现在假设有位置,所以this.tasks.shift()队列出一人 然后
p().then(resolve, reject)
.finally(() => {
this.runingCount--;
this._run();
})
then方法,执行回调,可以知道当前请求结束。不管成功还是失败,最终办理完成要出柜台,所以this.runingCount--;但是这样位置就空了,所以还得让排队的人来柜台,所以this._run();递归调用 完整
class Tasks {
constructor(optins = {}) {
const { maxTask = 3 } = optins;//最大并发数:默认同时请求三个
this.maxTask = maxTask;
this.tasks = [];//队列
this.runingCount = 0;//正在请求的个数
}
add(p) {
return new Promise((resolve, reject) => {
this.tasks.push({
p,
resolve,
reject
})
this._run();
})
}
_run() {
if (this.tasks.length !== 0 && this.runingCount < this.maxTask) {
this.runingCount++;
const { p, resolve, reject } = this.tasks.shift();
p().then(resolve, reject)
.finally(() => {
this.runingCount--;
this._run();
})
}
}
}
//模拟请求函数
function ajax(){
console.log('请求中')
return new Promise((resolve,reject)=>{
setTimeout(() => {
resolve();
}, Math.floor(Math.random()*5+1)*1000);//为了看真实情况,模拟了随机数,每个请求完成时间是随机的
})
}
const tasks = new Tasks();
//依此添加到队列
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax())
tasks.add(() => ajax()).then(() => {
console.log('终于完成')
})