{"id":13448530,"url":"https://github.com/charto/cwait","last_synced_at":"2025-04-05T20:09:12.077Z","repository":{"id":88491865,"uuid":"55068140","full_name":"charto/cwait","owner":"charto","description":":hourglass: Limit number of promises running in parallel","archived":false,"fork":false,"pushed_at":"2018-11-06T20:39:50.000Z","size":31,"stargazers_count":200,"open_issues_count":1,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-29T19:08:35.544Z","etag":null,"topics":["promise"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-30T14:05:19.000Z","updated_at":"2025-02-16T03:11:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"1ebe1297-cbfa-484c-bbdb-defa852a4803","html_url":"https://github.com/charto/cwait","commit_stats":{"total_commits":29,"total_committers":2,"mean_commits":14.5,"dds":0.03448275862068961,"last_synced_commit":"1ab8a54360ed456e35d6c9103a8f57de7856cac5"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charto%2Fcwait","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charto%2Fcwait/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charto%2Fcwait/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charto%2Fcwait/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charto","download_url":"https://codeload.github.com/charto/cwait/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393572,"owners_count":20931813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["promise"],"created_at":"2024-07-31T05:01:48.129Z","updated_at":"2025-04-05T20:09:12.030Z","avatar_url":"https://github.com/charto.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"cwait\n=====\n\n[![build status](https://travis-ci.org/charto/cwait.svg?branch=master)](http://travis-ci.org/charto/cwait)\n[![npm monthly downloads](https://img.shields.io/npm/dm/cwait.svg)](https://www.npmjs.com/package/cwait)\n[![npm version](https://img.shields.io/npm/v/cwait.svg)](https://www.npmjs.com/package/cwait)\n\n`cwait` provides a queue handler ([`TaskQueue`](#api-TaskQueue)) and a wrapper ([`Task`](#api-Task)) for promises,\nto limit how many are being resolved simultaneously. It can wrap any ES6-compatible promises.\nThis allows for example limiting simultaneous downloads with minor changes to existing code.\nJust wrap your existing \"download finished\" promise and use it as before.\n\nThis is a tiny library with a single dependency, usable both in browsers and Node.js.\n\nUsage\n-----\n\nCreate a new `TaskQueue` passing it whatever `Promise` constructor you're using (ES6, Bluebird, some other shim...)\nand the maximum number of promise-returning functions to run concurrently.\nThen just call `queue.wrap(\u003cfunction\u003e)` instead of `\u003cfunction\u003e` to limit simultaneous execution.\n\nSimple Node.js example:\n\n```TypeScript\nimport * as Promise from 'bluebird';\nimport {TaskQueue} from 'cwait';\n\n/** Queue allowing 3 concurrent function calls. */\nvar queue = new TaskQueue(Promise, 3);\n\nPromise.map(list, download); // Download all listed files simultaneously.\n\nPromise.map(list, queue.wrap(download)); // Download 3 files at a time.\n```\n\nSee [`test/test.ts`](test/test.ts) for some runnable code or run it like this:\n\n```sh\ngit clone https://github.com/charto/cwait.git\ncd cwait\nnpm install\nnpm test\n```\n\nRecursion\n---------\n\nRecursive loops that run in parallel require special care.\nNested concurrency-limited calls (that are not tail-recursive) must be wrapped in `queue.unblock()`.\n\nHere's a simple example that fails:\n\n```JavaScript\nvar queue = new (require('cwait').TaskQueue)(Promise, 3);\n\nvar rec = queue.wrap(function(n) {\n    console.log(n);\n    return(n \u0026\u0026 Promise.resolve(rec(n - 1)));\n});\n\nrec(10);\n```\n\nIt only prints numbers 10, 9 and 8.\nMore calls don't get scheduled because there are already 3 promises pending.\nFor example Node.js exits immediately afterwards because the program is not blocked waiting for any system calls.\n\nPassing a promise to `queue.unblock(promise)` tells `queue` that\nthe current function will wait for `promise` to resolve before continuing.\nOne additional concurrent function is then allowed until the promise resolves.\n\nBe careful not to call `queue.unblock()` more than once (concurrently) from inside a wrapped function!\nOtherwise the queue may permit more simultaneous tasks than the intended limit.\n\nHere is a corrected example:\n\n```JavaScript\nvar queue = new (require('cwait').TaskQueue)(Promise, 3);\n\nvar rec = queue.wrap(function(n) {\n    console.log(n);\n    return(n \u0026\u0026 queue.unblock(Promise.resolve(rec(n - 1))));\n});\n\nrec(10);\n```\n\nAdvanced example with recursion\n-------------------------------\n\nThe following code recursively calculates the 10th Fibonacci number (55)\nrunning 3 recursive steps in parallel, each with an artificial 10-millisecond delay.\n\nAt the end, it prints the result (55) and the number of concurrent calls (3).\n\n```JavaScript\nvar queue = new (require('cwait').TaskQueue)(Promise, 3);\n\nvar maxRunning = 0;\nvar running = 0;\nvar delay = 10;\n\nvar fib = queue.wrap(function(n) {\n    // \"Calculation\" begins. Track maximum concurrent executions.\n    if(++running \u003e maxRunning) maxRunning = running;\n\n    return(new Promise(function(resolve, reject) {\n        setTimeout(function() {\n            // \"Calculation\" ends.\n            --running;\n\n            // Each Fibonacci number is the sum of the previous two, except\n            // the first ones are 0, 1 (starting from the 0th number).\n            // Calculate them in parallel and unblock the queue until ready.\n\n            resolve(n \u003c 2 ? n :\n                queue.unblock(Promise.all([\n                    fib(n - 1),\n                    fib(n - 2)\n                ])).then(function(r) {\n                    // Sum results from parallel recursion.\n                    return(r[0] + r[1]);\n                })\n            );\n        }, delay);\n    }));\n});\n\nfib(10).then(function(x) {\n    console.log('Result: ' + x);\n    console.log('Concurrency: ' + maxRunning);\n});\n```\n\nAPI\n===\nDocs generated using [`docts`](https://github.com/charto/docts)\n\n\n\u003e\n\u003e \u003ca name=\"api-Task\"\u003e\u003c/a\u003e\n\u003e ### Class [`Task`](#api-Task)\n\u003e \u003cem\u003eTask wraps a promise, delaying it until some resource gets less busy.\u003c/em\u003e  \n\u003e Source code: [`\u003c\u003e`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L49-L80)  \n\u003e  \n\u003e Methods:  \n\u003e \u003e **new( )** \u003csup\u003e\u0026rArr; \u003ccode\u003e[Task](#api-Task)\u0026lt;PromiseType\u0026gt;\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L50-L53)  \n\u003e \u003e \u0026emsp;\u0026#x25aa; func \u003csup\u003e\u003ccode\u003e() =\u0026gt; PromiseType\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; Promise \u003csup\u003e\u003ccode\u003e[PromisyClass](#api-PromisyClass)\u0026lt;PromiseType\u0026gt;\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e **.delay( )** \u003csup\u003e\u0026rArr; \u003ccode\u003ePromiseType\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L57-L66)  \n\u003e \u003e \u0026emsp;\u003cem\u003eWrap task result in a new promise so it can be resolved later.\u003c/em\u003e  \n\u003e \u003e **.resume( )** \u003csup\u003e\u0026rArr; \u003ccode\u003ePromiseType\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/bcc3b2b/src/Task.ts#L70-L72)  \n\u003e \u003e \u0026emsp;\u003cem\u003eStart the task and call onFinish when done.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; onFinish \u003csup\u003e\u003ccode\u003e() =\u0026gt; void\u003c/code\u003e\u003c/sup\u003e  \n\u003e\n\u003e \u003ca name=\"api-TaskQueue\"\u003e\u003c/a\u003e\n\u003e ### Class [`TaskQueue`](#api-TaskQueue)\n\u003e Source code: [`\u003c\u003e`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L6-L75)  \n\u003e  \n\u003e Methods:  \n\u003e \u003e **new( )** \u003csup\u003e\u0026rArr; \u003ccode\u003e[TaskQueue](#api-TaskQueue)\u0026lt;PromiseType\u0026gt;\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L7-L11)  \n\u003e \u003e \u0026emsp;\u0026#x25aa; Promise \u003csup\u003e\u003ccode\u003e[PromisyClass](#api-PromisyClass)\u0026lt;PromiseType\u0026gt;\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; concurrency \u003csup\u003e\u003ccode\u003enumber\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e **.add( )** \u003csup\u003e\u0026rArr; \u003ccode\u003ePromiseType\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L16-L33)  \n\u003e \u003e \u0026emsp;\u003cem\u003eAdd a new task to the queue.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u003cem\u003eIt will start when the number of other concurrent tasks is low enough.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; func \u003csup\u003e\u003ccode\u003e() =\u0026gt; PromiseType\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e **.unblock( )** \u003csup\u003e\u0026rArr; \u003ccode\u003ePromiseType\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L38-L46)  \n\u003e \u003e \u0026emsp;\u003cem\u003eConsider current function idle until promise resolves.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u003cem\u003eUseful for making recursive calls.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; promise \u003csup\u003e\u003ccode\u003ePromiseType\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e **.wrap( )** \u003csup\u003e\u0026rArr; \u003ccode\u003e(...args: any[]) =\u0026gt; PromiseType\u003c/code\u003e\u003c/sup\u003e [`\u003c\u003e`](http://github.com/charto/cwait/blob/c57c0fd/src/TaskQueue.ts#L51-L53)  \n\u003e \u003e \u0026emsp;\u003cem\u003eWrap a function returning a promise, so that before running\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u003cem\u003eit waits until concurrent invocations are below this queue's limit.\u003c/em\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25aa; func \u003csup\u003e\u003ccode\u003e(...args: any[]) =\u0026gt; PromiseType\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e \u0026emsp;\u0026#x25ab; thisObject\u003csub\u003e?\u003c/sub\u003e \u003csup\u003e\u003ccode\u003eany\u003c/code\u003e\u003c/sup\u003e  \n\u003e  \n\u003e Properties:  \n\u003e \u003e **.concurrency** \u003csup\u003e\u003ccode\u003enumber\u003c/code\u003e\u003c/sup\u003e  \n\u003e \u003e \u0026emsp;\u003cem\u003eNumber of promises allowed to resolve concurrently.\u003c/em\u003e  \n\nLicense\n=======\n\n[The MIT License](https://raw.githubusercontent.com/charto/cwait/master/LICENSE)\n\nCopyright (c) 2015-2017 BusFaster Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharto%2Fcwait","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharto%2Fcwait","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharto%2Fcwait/lists"}