JavaScript请求并发限制器

303 阅读1分钟
class RequestPool {
  constructor({ max, asyncFun, debug = false }) {
    // 最大并发数
    this.max = max;
    // 请求池
    this.pool = [];
    // 全部的请求参数
    this.urls = [];
    // 请求函数
    this.asyncFun = asyncFun;
    // debug
    this.debug = debug;
  }

  // 传入请求队列参数,所有请求完成后的回调函数
  step(urls, onFulfilledCallback) {
    this.urls = urls;
    this.onFulfilledCallback = onFulfilledCallback ? onFulfilledCallback : () => {};
    while (this.pool.length < this.max && this.urls.length > 0) {
      const params = this.urls.shift();
      this.setTask(params);
    }
    this.run(Promise.race(this.pool));
  }

  // 通过race监听请求,完成则添加新的请求,并再次监听
  run(race) {
    race.then(() => {
      const params = this.urls.shift();
      this.setTask(params);
      this.run(Promise.race(this.pool));
    })
  }

  // 添加任务到池里,任务完成删除池子里的任务
  setTask(params) {
    if (!params) {
      return;
    }
    const task = this.asyncFun(params);
    this.pool.push(task);
    this.log('start');
    task.then(() => {
      const index = this.pool.indexOf(task);
      this.pool.splice(index, 1);
      this.log('end');
      if (this.pool.length === 0) {
        this.onFulfilledCallback();
      }
    })
  }

  // 日志
  log(state) {
    if (!this.debug) {
      return;
    }

    if (state === 'start') {
      console.log(`%c请求开始,进行中的请求数量${this.pool.length},剩余请求数量${this.urls.length}`, 'color:#E6A23C');
    }

    if (state === 'end') {
      console.log(`%c请求完成,进行中的请求数量${this.pool.length},剩余请求数量${this.urls.length}`, 'color:#67C23A');
    }
  }
}

使用

const pool = new RequestPool({
  max: 3,
  asyncFun: asyncFun,
  debug: true
})

function asyncFun(num) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(num)
    }, Math.random() * 1000 + 2000)
  })
}

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
pool.step(nums, () => {
  console.log(`%c全部请求完成`, 'color:#67C23A')
});