【源码共读】p-limit 限制并发数

397 阅读1分钟

前言:p-limit源码阅读计划 请查看若川视野 x 源码共读

  • 入参

concurrency接受一个大于等于1的number类型的值,如果不合法会抛出异常

  • 创建一个队列

const queue = new Queue();创建队列使用了yocto-queue这个库

  • activeCount 标记队列中还有多少正在执行的函数个数
  • next 函数

执行的是队列中的出站函数

const next = () => {
    activeCount--;
    if (queue.size > 0) {
       queue.dequeue()();
    }
};
  • run 函数

依次往队列中增加函数并执行

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

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

        resolve(result);

        try {
            await result;
	} catch {}

	next();
};
  • enqueue 函数

通过 yocto-queue 管理队列里面的函数并绑定上下文

const enqueue = (fn, resolve, args) => {
    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()();
    }
    })();
};
  • 返回一个Promise函数的返回值

构建了一个Promise的返回函数,并附加了三个属性: activeCount 标记队列中还有多少正在执行的函数个数 pendingCount 队列等待执行的函数有多少个 clearQueue 清空队列

const generator = (fn, ...args) => new Promise(resolve => {
    enqueue(fn, resolve, args);
});

Object.defineProperties(generator, {
    activeCount: {
        get: () => activeCount,
    },
    pendingCount: {
	get: () => queue.size,
    },
    clearQueue: {
	value: () => {
            queue.clear();
	},
    },
});