You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
1.5 KiB
71 lines
1.5 KiB
'use strict'; |
|
const Queue = require('yocto-queue'); |
|
|
|
const pLimit = concurrency => { |
|
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) { |
|
throw new TypeError('Expected `concurrency` to be a number from 1 and up'); |
|
} |
|
|
|
const queue = new Queue(); |
|
let activeCount = 0; |
|
|
|
const next = () => { |
|
activeCount--; |
|
|
|
if (queue.size > 0) { |
|
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) => { |
|
queue.enqueue(run.bind(null, 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()(); |
|
} |
|
})(); |
|
}; |
|
|
|
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(); |
|
} |
|
} |
|
}); |
|
|
|
return generator; |
|
}; |
|
|
|
module.exports = pLimit;
|
|
|