diff --git a/index.d.ts b/index.d.ts index 038ba41..34b1be2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -41,3 +41,41 @@ Run multiple promise-returning & async functions with limited concurrency. @returns A `limit` function. */ export default function pLimit(concurrency: number): LimitFunction; + +export type Options = { + /** + Concurrency limit. + + Minimum: `1`. + */ + readonly concurrency: number; +}; + +/** +Returns a function with limited concurrency. + +The returned function manages its own concurrent executions, allowing you to call it multiple times without exceeding the specified concurrency limit. + +Ideal for scenarios where you need to control the number of simultaneous executions of a single function, rather than managing concurrency across multiple functions. + +@param function_ - Promise-returning/async function. +@return Function with limited concurrency. + +@example +``` +import {limitFunction} from 'p-limit'; + +const limitedFunction = limitFunction(async () => { + return doSomething(); +}, {concurrency: 1}); + +const input = Array.from({length: 10}, limitedFunction); + +// Only one promise is run at once. +await Promise.all(input); +``` +*/ +export function limitFunction( + function_: (...arguments_: Arguments) => PromiseLike | ReturnType, + option: Options +): (...arguments_: Arguments) => Promise; diff --git a/index.js b/index.js index 484ad3e..22b1e87 100644 --- a/index.js +++ b/index.js @@ -90,6 +90,13 @@ export default function pLimit(concurrency) { return generator; } +export function limitFunction(function_, option) { + const {concurrency} = option; + const limit = pLimit(concurrency); + + return (...arguments_) => limit(() => function_(...arguments_)); +} + function validateConcurrency(concurrency) { if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) { throw new TypeError('Expected `concurrency` to be a number from 1 and up'); diff --git a/readme.md b/readme.md index df0af3f..c285926 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ console.log(result); ## API -### pLimit(concurrency) +### pLimit(concurrency) default export Returns a `limit` function. @@ -77,6 +77,44 @@ Note: This does not cancel promises that are already running. Get or set the concurrency limit. +### limitFunction(fn, options) named export + +Returns a function with limited concurrency. + +The returned function manages its own concurrent executions, allowing you to call it multiple times without exceeding the specified concurrency limit. + +Ideal for scenarios where you need to control the number of simultaneous executions of a single function, rather than managing concurrency across multiple functions. + +```js +import {limitFunction} from 'p-limit'; + +const limitedFunction = limitFunction(async () => { + return doSomething(); +}, {concurrency: 1}); + +const input = Array.from({length: 10}, limitedFunction); + +// Only one promise is run at once. +await Promise.all(input); +``` + +#### fn + +Type: `Function` + +Promise-returning/async function. + +#### options + +Type: `object` + +#### concurrency + +Type: `number`\ +Minimum: `1` + +Concurrency limit. + ## FAQ ### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package? diff --git a/test.js b/test.js index 08bb306..373d67b 100644 --- a/test.js +++ b/test.js @@ -4,7 +4,7 @@ import delay from 'delay'; import inRange from 'in-range'; import timeSpan from 'time-span'; import randomInt from 'random-int'; -import pLimit from './index.js'; +import pLimit, {limitFunction} from './index.js'; test('concurrency: 1', async t => { const input = [ @@ -217,3 +217,19 @@ test('change concurrency to bigger value', async t => { await Promise.all(promises); t.deepEqual(log, [1, 2, 3, 4, 4, 4, 4, 4, 4, 4]); }); + +test('limitFunction()', async t => { + const concurrency = 5; + let running = 0; + + const limitedFunction = limitFunction(async () => { + running++; + t.true(running <= concurrency); + await delay(randomInt(30, 200)); + running--; + }, {concurrency}); + + const input = Array.from({length: 100}, limitedFunction); + + await Promise.all(input); +});