concurrency-limiter
DefinitelyTyped icon, indicating that this package has TypeScript declarations provided by the separate @types/concurrency-limiter package

0.1.0 • Public • Published

Build Status

concurrency-limiter

Limit the number of asynchronous concurrent tasks running.

Goals

Assume you need to connect to many different WebSocket servers, or retrieve many resources concurrently at the same time. Any asynchronous operation can be started easily with JavaScript, but when too many of them could potentially be executed at the same time it's usually a good idea to limit their number to avoid resource consumption on the browser or the node instance.

Limiting the number of concurrent asynchronous tasks running is the goal of concurrency-limiter.

Getting started

Instantiate a limiter passing the number of allowed concurrent tasks:

const Limiter = require('concurrency-limiter');
 
const limiter = new Limiter(10);

The limiter created in the code above allows 10 concurrent tasks to be executed together. Awaiting limiter.enter() ensures that subsequent code is only executed when a slot becomes available. The promise returned by enter() is only resolved when less than 10 tasks are running. When a task is complete, the slot can be released by calling limiter.exit(), like in this example:

async function run() {
    await limiter.enter(); // This will "block" until a slot is available.
    await myAsyncTask();
    limiter.exit(); // This releases the slot.
}

The code above ensures that only 10 calls to myAsyncTask() are executed concurrently. Any additional calls will have to wait for a slot to be available. Note that there is no limit to what can be executed between enter() and exit().

It's very important to ensure that, for every enter() call, the corresponding exit() one is also eventually executed, otherwise an acquired slot would never be released. For that reason, the example above should be more correctly written as:

async function run() {
    await limiter.enter();
    try {
        await myAsyncTask();
    } finally {
        limiter.exit();
    }
}

In the simple case a single async function must be executed in limited concurrency, when entering the limiter must be done right before the function is called and exiting right after, limiter.run() can be used instead. The above can be rewritten as:

async function run() {
    await limiter.run(myAsyncTask);
}

The run() method will release the slot even in the case myAsyncTask raises an exception. Also, the awaited result of myAsyncTask is returned.

API reference

Limiter(limit) ⇒ Object

The concurrency limiter.

It is instantiated providing the maximum number of async tasks that are allowed to run concurrently. It has the following methods:

enter() ⇒ Promise

Request a slot for concurrent execution. The returned promise is only resolved when a slot becomes available. The promise is never rejected. This method is usually called before starting an async operation, like:

    await limiter.enter();
    await wsConnect();
    ...
    wsClose();
    limiter.exit();

@returns {Promise} A promise resolved when a slot is available.

exit()

Release a slot for concurrent execution. This method is usually called after an async operation completes.

run(func) ⇒ Promise

Execute the provided async function when a concurrent slot is available, and release the slot when the function completes, returning its result. The limiter is exited even in the case the function raises an exception.

@param {Function} func A function to be awaited when an async slot is available. @returns {Any} The result returned by awaiting the provided function.

Package Sidebar

Install

npm i concurrency-limiter

Weekly Downloads

10

Version

0.1.0

License

MIT

Unpacked Size

12.6 kB

Total Files

8

Last publish

Collaborators

  • frankban