p-limit 限制并发数

447 阅读2分钟

1.p-limit介绍

Run multiple promise-returning & async functions with limited concurrency

以有限的并发运行多个异步函数,高并发会占用过多资源,影响其他进程。

2.p-limit使用

import pLimit from 'p-limit';

const limit = pLimit(1);

const input = [
	limit(() => fetchSomething('foo')),
	limit(() => fetchSomething('bar')),
	limit(() => doSomething())
];

// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);

3.p-limit代码

import Queue from "yocto-queue";

export default function pLimit(concurrency) {
    //判断并发数的类型是否是数字
  if (
    !(
      (Number.isInteger(concurrency) ||
        concurrency === Number.POSITIVE_INFINITY) &&
      concurrency > 0
    )
  ) {
    throw new TypeError("Expected `concurrency` to be a number from 1 and up");
  }
// 建立一个队列,Queue为链表
  const queue = new Queue();
  //当前执行任务的个数
  let activeCount = 0;

  const next = () => {
    activeCount--;
    //执行完成,当前异步任务数量减一
    if (queue.size > 0) {
        // 队列的第一个出队并执行run函数
      queue.dequeue()();
    }
  };

  const run = async (fn, resolve, args) => {
    activeCount++;

    const result = (async () => fn(...args))();

    resolve(result);

    try {
      await result;
    } catch {}

    next();
  };

  const enqueue = (fn, resolve, args) => {
    //将函数放入队列中,bind生成一个新的函数,this指向为undefined
    queue.enqueue(run.bind(undefined, fn, resolve, args));

    (async () => {
      // This function needs to wait until the next microtask before comparing
      // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
      // when the run function is dequeued and called. The comparison in the if-statement
      // needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
      await Promise.resolve();
    //若当前执行的异步任务个数小于并发限制的数量,继续执行
      if (activeCount < concurrency && queue.size > 0) {
        queue.dequeue()();//执行run()
      }
    })();
  };

  const generator = (fn, ...args) =>
    new Promise((resolve) => {
     // 将异步函数放入队列
      enqueue(fn, resolve, args);
    });
 //监听generator里面的属性
  Object.defineProperties(generator, {
    activeCount: {
      get: () => activeCount,
    },
    pendingCount: {
      get: () => queue.size,
    },
    clearQueue: {
      value: () => {
        queue.clear();
      },
    },
  });
 //返回一个promise 函数
  return generator;
}

4.promise.all方法

function (values) {
    // promise 以第一个结果为准,其它的逻辑还是走,只是不采纳了
    return new Promise((resolve, reject) => {
      // 并发是循环  串行递归
      let arr = [];
      let times = 0;
      function processData(index, data) {
        arr[index] = data; 
        if (++times === values.length) {
          resolve(arr);
        }

      }

      for (let i = 0; i < values.length; i++) {
        let cur = values[i];
        Promise.resolve(cur).then((data) => {
          processData(i, data);
        }, reject);
      }
    });
  };