如何实现一个并发请求控制

175 阅读1分钟

描述

实现一个任务队列和执行队列,执行队列只能同时执行一些任务,当某一个任务执行完成后才会从任务队列中去取出一条任务去执行

应用场景

例如前端大文件上传功能经常会用到分片上传,假如单片2Mb,1G文件上传需要上传512次,单片单片上传速度很慢,一次性并发数又太高,这时候能将并发请求控制在一定数量内,既能保证传输速度又可以不过高损耗服务器性能

实现

首先我们先用一个定时器函数模拟接口请求

function _timeout(time) {
  return new Promise((reslove, reject) => {
    setTimeout(() => {
      reslove();
    }, time);
  });
}

现在创建一个类来简易实现

function _timeout(time) {
  return new Promise((reslove, reject) => {
    setTimeout(() => {
      reslove();
    }, time);
  });
}

class SuperTask {
  constructor(limit = 2) {
    this.limit = limit; // 设置执行队列中允许同时执行任务的数量
    this.taskQueue = []; // 用于存储的任务队列
    this.executeNum = 0; // 执行队列中的任务数量
  }

  addTask(time, fn) {
    // 往taskQueue中添加任务
    this.add(() => _timeout(time)).then(() => {
      fn();
    });
  }

  add(fn) {
    return new Promise((reslove, reject) => {
      this.taskQueue.push({
        fn,
        reslove,
        reject,
      });
      this._run();
    });
  }

  _run() {
    while (this.limit > this.executeNum && this.taskQueue.length > 0) {
      const { fn, reslove, reject } = this.taskQueue.shift(); // 每次从taskQueue中取第一个排队任务
      this.executeNum++;
      fn().then(() => {
        // 任务是一个promise
        reslove();
        this.executeNum--;
        this._run();
      });
    }
  }
}

const superTask = new SuperTask();

superTask.addTask(10000, () => {
  console.log("任务1结束");
}); //10000ms输出,任务1结束
superTask.addTask(5000, () => {
  console.log("任务2结束");
}); //5000ms输出,任务2结束
superTask.addTask(3000, () => {
  console.log("任务3结束");
}); //8000ms输出,任务3结束
superTask.addTask(4000, () => {
  console.log("任务4结束");
}); //12000ms输出,任务4结束
superTask.addTask(5000, () => {
  console.log("任务5结束");
}); //15000ms输出,任务5结束