JS异步任务池,实现多任务并行的控制

2,025 阅读1分钟

这个是从git上找到的一个实现异步池的方法

function asyncPool(poolLimit, array, iteratorFn) {
  let i = 0;
  const ret = [];
  const executing = [];
  const enqueue = function() {
    if (i === array.length) {
      return Promise.resolve();
    }
    const item = array[i++];
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p);
    let r = Promise.resolve();
    if (poolLimit <= array.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= poolLimit) {
        r = Promise.race(executing);
      }
    }
    return r.then(() => enqueue());
  };
  return enqueue().then(() => Promise.all(ret));
}

poolLimit:并行最大任务数 array:迭代数组 iteratorFn:迭代执行函数 缺点是只能传一个固定的异步方法,然后将参数都放在一个数组内,用起来不方便。

参考前人的经验,我实现了一个可随时添加新任务到等待队列的任务池,按照入队顺序将任务放入任务池执行

class AsyncPool {
  executing = [];
  constructor(poolLimit) {
    this.poolLimit = poolLimit || 5;
  }
  //promiseCreator:返回值为promise的任务函数
  add(promiseCreator) {
    if (this.executing.length < this.poolLimit) {
      const p = Promise.resolve().then(() => promiseCreator());
      const e = p.then((res) => {
        this.executing.splice(this.executing.indexOf(e), 1);
        return res;
      });
      this.executing.push(e);
      return e;
    } else {
      const race = Promise.race(this.executing);
      return race.then(() => this.add(promiseCreator));
    }
  }
}

测试:

const pool = new AsyncPool(2);
const startTime = new Date().getTime();
const createTask = (task, time) => () =>
  new Promise((resolve) => {
    const endTime = new Date().getTime() - startTime;
    console.log(`${endTime}ms--------${task}开始执行`);
    setTimeout(() => {
      resolve();
      const endTime = new Date().getTime() - startTime;
      console.log(`${endTime}ms--------${task}执行完毕,花费${time}ms`);
    }, time);
  }).catch((err) => {});
const task1 = createTask("task1", 100);
const task2 = createTask("task2", 500);
const task3 = createTask("task3", 300);
const task4 = createTask("task4", 100);
pool.add(task1);
pool.add(task2);
pool.add(task3);
pool.add(task4);

image.png