promise限制异步操作并发数

6 阅读1分钟

可以使用Promise 配合异步函数和队列来实现对异步操作的并发数限制。核心思想是维护一个正在执行的异步操作计数器,以及一个等待执行的异步操作队列。当有新的异步操作需要执行时,如果并发数未超过限制,则立即执行;否则,将该操作放入队列等待。当某个异步操作完成时,从队列中取出一个新的操作执行,以此来控制并发量。

class LimitConcurrency {
  constructor(limit) {
    this.limit = limit; // 并发限制数
    this.count = 0; // 当前正在执行的异步操作数量
    this.queue = []; // 等待执行的异步操作队列
  }

  // 添加一个异步操作
  async add(fn) {
    return new Promise((resolve, reject) => {
      const task = async () => {
        this.count++;
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        } finally {
          this.count--;
          this.run(); // 执行下一个任务
        }
      };

      if (this.count < this.limit) {
        task();
      } else {
        this.queue.push(task);
      }
    });
  }

  // 运行下一个任务
  run() {
    if (this.queue.length > 0 && this.count < this.limit) {
      const task = this.queue.shift();
      task();
    }
  }
}

// 示例
async function asyncTask(i, delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`Task ${i} finished`);
      resolve(i);
    }, delay);
  });
}

async function main() {
  const concurrencyLimit = 2;
  const limit = new LimitConcurrency(concurrencyLimit);

  const tasks = [
    () => asyncTask(1, 2000),
    () => asyncTask(2, 1000),
    () => asyncTask(3, 1500),
    () => asyncTask(4, 500),
    () => asyncTask(5, 1200),
  ];

  const results = await Promise.all(
    tasks.map(task => limit.add(task))
  );

  console.log("All tasks finished", results);
}

main();

LimitConcurrency 类用于控制并发数。add 方法接受一个异步函数作为参数,并将其添加到队列或立即执行。run 方法用于从队列中取出任务并执行。通过 Promise.all 确保所有任务都完成。