字节:实现一下并发请求

69 阅读2分钟

理解: 先举个例子,假设我们去银行办业务。有两个柜台,这就是最大并发数。当我们去的时候,先抽号排队,然后再去柜台。

情况一: 截屏2023-11-17 上午1.48.52.png 柜台没人,这时候第一个人可以直接去,也就是当柜台没有人,直接去。

第二种情况:柜台满了,只能排队 截屏2023-11-17 上午1.51.16.png

第三种情况

截屏2023-11-17 上午1.52.44.png 柜台有人离开,那么后面的接着上。 这里的柜台,就是最大并发数,同时只能办理两个人,排队就是一个队列,当有空位出现,先进的先出。 当所有人办理结束,那么整体情况也结束。

实现思路: 首先定义maxTask:最大并发数,tasks:队列,runingCount:正在请求个数 add方法:当有请求过来,就进入排队,然后看看要不要去柜台办理,所以用run方法 run方法:

  1. 首先判断柜台有没有位置:this.runingCount < this.maxTask,如果有位置,直接排队的人出一个去柜台办理,如果没位置,就不处理
  2. 判断排队还有没有人: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('终于完成')
})