import Queue from 'yocto-queue';
2
3export default function pLimit(concurrency) {
4 validateConcurrency(concurrency);
5
6 const queue = new Queue();
7 let activeCount = 0;
8
9 const resumeNext = () => {
10 if (activeCount < concurrency && queue.size > 0) {
11 queue.dequeue()();
12
13 activeCount++;
14 }
15 };
16
17 const next = () => {
18 activeCount--;
19
20 resumeNext();
21 };
22
23 const run = async (function_, resolve, arguments_) => {
24 const result = (async () => function_(...arguments_))();
25
26 resolve(result);
27
28 try {
29 await result;
30 } catch {}
31
32 next();
33 };
34
35 const enqueue = (function_, resolve, arguments_) => {
36
37
38 new Promise(internalResolve => {
39 queue.enqueue(internalResolve);
40 }).then(
41 run.bind(undefined, function_, resolve, arguments_),
42 );
43
44 (async () => {
45
46
47
48
49 await Promise.resolve();
50
51 if (activeCount < concurrency) {
52 resumeNext();
53 }
54 })();
55 };
56
57 const generator = (function_, ...arguments_) => new Promise(resolve => {
58 enqueue(function_, resolve, arguments_);
59 });
60
61 Object.defineProperties(generator, {
62 activeCount: {
63 get: () => activeCount,
64 },
65 pendingCount: {
66 get: () => queue.size,
67 },
68 clearQueue: {
69 value() {
70 queue.clear();
71 },
72 },
73 concurrency: {
74 get: () => concurrency,
75
76 set(newConcurrency) {
77 validateConcurrency(newConcurrency);
78 concurrency = newConcurrency;
79
80 queueMicrotask(() => {
81
82 while (activeCount < concurrency && queue.size > 0) {
83 resumeNext();
84 }
85 });
86 },
87 },
88 });
89
90 return generator;
91}
92
93function validateConcurrency(concurrency) {
94 if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
95 throw new TypeError('Expected `concurrency` to be a number from 1 and up');
96 }
97}
import pLimit from 'p-limit';
const limit = pLimit(1);
const input = [
limit(() => fetchSomething('foo')),
limit(() => fetchSomething('bar')),
limit(() => doSomething())
];
const result = await Promise.all(input);
console.log(result);