# cwait

> Limit number of promises running in parallel

Latest version **1.1.2** (published 2018-11-06) · MIT license · 21.4K weekly downloads

## Install

```sh
npm install cwait
pnpm add cwait
yarn add cwait
bun add cwait
```

## Health

**Score 40/100 (D)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.1.2 |
| Published | 2018-11-06 |
| First published | 2016-03-30 |
| Weekly downloads | 21.4K |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 32.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 200 |
| Author | Juha Järvi |
| Maintainers | jjrv |
| Keywords | promise, concurrent, concurrency, parallel, timeout, delay, wait, queue |

## Links

- npm: https://www.npmjs.com/package/cwait
- Repository: https://github.com/charto/cwait
- Homepage: https://github.com/charto/cwait#readme
- Issues: https://github.com/charto/cwait/issues
- npm.io page: https://npm.io/package/cwait

## Dependencies (1)

- [cdata](https://npm.io/package/cdata.md) ^0.1.1

## Alternatives

- [@commercetools/sync-actions](https://npm.io/package/@commercetools/sync-actions.md) — 25.1K weekly downloads
- [@ledgerhq/hw-app-cosmos](https://npm.io/package/@ledgerhq/hw-app-cosmos.md) — 4.2K weekly downloads
- [@financial-times/o-loading](https://npm.io/package/@financial-times/o-loading.md) — 2.8K weekly downloads
- [fa](https://npm.io/package/fa.md) — 185 weekly downloads
- [@quenty/grouputils](https://npm.io/package/@quenty/grouputils.md) — 80 weekly downloads

## Recent versions

- 1.1.2 (latest) — 2018-11-06
- 1.1.1 — 2017-08-06
- 1.1.0 — 2017-07-13
- 1.0.1 — 2016-12-14
- 1.0.0 — 2016-05-10
- 0.0.3 — 2016-05-04
- 0.0.2 — 2016-04-02
- 0.0.1 — 2016-03-30

## README

cwait
=====

[![build status](https://travis-ci.org/charto/cwait.svg?branch=master)](http://travis-ci.org/charto/cwait)
[![npm monthly downloads](https://img.shields.io/npm/dm/cwait.svg)](https://www.npmjs.com/package/cwait)
[![npm version](https://img.shields.io/npm/v/cwait.svg)](https://www.npmjs.com/package/cwait)

`cwait` provides a queue handler ([`TaskQueue`](#api-TaskQueue)) and a wrapper ([`Task`](#api-Task)) for promises,
to limit how many are being resolved simultaneously. It can wrap any ES6-compatible promises.
This allows for example limiting simultaneous downloads with minor changes to existing code.
Just wrap your existing "download finished" promise and use it as before.

This is a tiny library with a single dependency, usable both in browsers and Node.js.

Usage
-----

Create a new `TaskQueue` passing it whatever `Promise` constructor you're using (ES6, Bluebird, some other shim...)
and the maximum number of promise-returning functions to run concurrently.
Then just call `queue.wrap(<function>)` instead of `<function>` to limit simultaneous execution.

Simple Node.js example:

```TypeScript
import * as Promise from 'bluebird';
import {TaskQueue} from 'cwait';

/** Queue allowing 3 concurrent function calls. */
var queue = new TaskQueue(Promise, 3);

Promise.map(list, download); // Download all listed files simultaneously.

Promise.map(list, queue.wrap(download)); // Download 3 files at a time.
```

See [`test/test.ts`](test/test.ts) for some runnable code or run it like this:

```sh
git clone https://github.com/charto/cwait.git
cd cwait
npm install
npm test
```

Recursion
---------

Recursive loops that run in parallel require special care.
Nested concurrency-limited calls (that are not tail-recursive) must be wrapped in `queue.unblock()`.

Here's a simple example that fails:

```JavaScript
var queue = new (require('cwait').TaskQueue)(Promise, 3);

var rec = queue.wrap(function(n) {
    console.log(n);
    return(n && Promise.resolve(rec(n - 1)));
});

rec(10);
```

It only prints numbers 10, 9 and 8.
More calls don't get scheduled because there are already 3 promises pending.
For example Node.js exits immediately afterwards because the program is not blocked waiting for any system calls.

Passing a promise to `queue.unblock(promise)` tells `queue` that
the current function will wait for `promise` to resolve before continuing.
One additional concurrent function is then allowed until the promise resolves.

Be careful not to call `queue.unblock()` more than once (concurrently) from inside a wrapped function!
Otherwise the queue may permit more simultaneous tasks than the intended limit.

Here is a corrected example:

```JavaScript
var queue = new (require('cwait').TaskQueue)(Promise, 3);

var rec = queue.wrap(function(n) {
    console.log(n);
    return(n && queue.unblock(Promise.resolve(rec(n - 1))));
});

rec(10);
```

Advanced example with recursion
-------------------------------

The following code recursively calculates the 10th Fibonacci number (55)
running 3 recursive steps in parallel, each with an artificial 10-millisecond delay.

At the end, it prints the result (55) and the number of concurrent calls (3).

```JavaScript
var queue = new (require('cwait').TaskQueue)(Promise, 3);

var maxRunning = 0;
var running = 0;
var delay = 10;

var fib = queue.wrap(function(n) {
    // "Calculation" begins. Track maximum concurrent executions.
    if(++running > maxRunning) maxRunning = running;

    return(new Promise(function(resolve, reject) {
        setTimeout(function() {
            // "Calculation" ends.
            --running;

            // Each Fibonacci number is the sum of the previous two, except
            // the first ones are 0, 1 (starting from the 0th number).
            // Calculate them in parallel and unblock the queue until ready.

            resolve(n < 2 ? n :
                queue.unblock(Promise.all([
                    fib(n - 1),
                    fib(n - 2)
                ])).then(function(r) {
                    // Sum results from parallel recursion.
                    return(r[0] + r[1]);
                })
            );
        }, delay);
    }));
});

fib(10).then(function(x) {
    console.log('Result: ' + x);
    console.log('Concurrency: ' + maxRunning);
});
```

API
===
Docs generated using [`docts`](https://github.com/charto/docts)


>
> <a name="api-Task"></a>
> ### Class [`Task`](#api-Task)
> <em>Task wraps a promise, delaying it until some resource gets less busy.</em>  
> Source code: [`<>`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L49-L80)  
>  
> Methods:  
> > **new( )** <sup>&rArr; <code>[Task](#api-Task)&lt;PromiseType&gt;</code></sup> [`<>`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L50-L53)  
> > &emsp;&#x25aa; func <sup><code>() =&gt; PromiseType</code></sup>  
> > &emsp;&#x25aa; Promise <sup><code>[PromisyClass](#api-PromisyClass)&lt;PromiseType&gt;</code></sup>  
> > **.delay( )** <sup>&rArr; <code>PromiseType</code></sup> [`<>`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L57-L66)  
> > &emsp;<em>Wrap task result in a new promise so it can be resolved later.</em>  
> > **.resume( )** <sup>&rArr; <code>PromiseType</code></sup> [`<>`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L70-L72)  
> > &emsp;<em>Start the task and call onFinish when done.</em>  
> > &emsp;&#x25aa; onFinish <sup><code>() =&gt; void</code></sup>  
>
> <a name="api-TaskQueue"></a>
> ### Class [`TaskQueue`](#api-TaskQueue)
> Source code: [`<>`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L6-L75)  
>  
> Methods:  
> > **new( )** <sup>&rArr; <code>[TaskQueue](#api-TaskQueue)&lt;PromiseType&gt;</code></sup> [`<>`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L7-L11)  
> > &emsp;&#x25aa; Promise <sup><code>[PromisyClass](#api-PromisyClass)&lt;PromiseType&gt;</code></sup>  
> > &emsp;&#x25aa; concurrency <sup><code>number</code></sup>  
> > **.add( )** <sup>&rArr; <code>PromiseType</code></sup> [`<>`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L16-L33)  
> > &emsp;<em>Add a new task to the queue.</em>  
> > &emsp;<em>It will start when the number of other concurrent tasks is low enough.</em>  
> > &emsp;&#x25aa; func <sup><code>() =&gt; PromiseType</code></sup>  
> > **.unblock( )** <sup>&rArr; <code>PromiseType</code></sup> [`<>`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L38-L46)  
> > &emsp;<em>Consider current function idle until promise resolves.</em>  
> > &emsp;<em>Useful for making recursive calls.</em>  
> > &emsp;&#x25aa; promise <sup><code>PromiseType</code></sup>  
> > **.wrap( )** <sup>&rArr; <code>(...args: any[]) =&gt; PromiseType</code></sup> [`<>`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L51-L53)  
> > &emsp;<em>Wrap a function returning a promise, so that before running</em>  
> > &emsp;<em>it waits until concurrent invocations are below this queue's limit.</em>  
> > &emsp;&#x25aa; func <sup><code>(...args: any[]) =&gt; PromiseType</code></sup>  
> > &emsp;&#x25ab; thisObject<sub>?</sub> <sup><code>any</code></sup>  
>  
> Properties:  
> > **.concurrency** <sup><code>number</code></sup>  
> > &emsp;<em>Number of promises allowed to resolve concurrently.</em>  

License
=======

[The MIT License](https://raw.githubusercontent.com/charto/cwait/master/LICENSE)

Copyright (c) 2015-2017 BusFaster Ltd

---
_Source: https://npm.io/package/cwait · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
