{"id":30071039,"url":"https://github.com/comfreek/async-playground","last_synced_at":"2025-10-04T22:42:00.220Z","repository":{"id":30059836,"uuid":"123799304","full_name":"ComFreek/async-playground","owner":"ComFreek","description":"Semaphores, critical sections and blocking queues explored in modern JS with Promises and async generators","archived":false,"fork":false,"pushed_at":"2025-09-26T04:38:26.000Z","size":4217,"stargazers_count":8,"open_issues_count":14,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-26T06:21:05.023Z","etag":null,"topics":["async-generators","asynchronous","asynchronous-programming","generator","modern-javascript","promises","semaphores","typescript"],"latest_commit_sha":null,"homepage":"https://comfreek.github.io/async-playground","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ComFreek.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-03-04T14:58:33.000Z","updated_at":"2025-08-25T16:41:23.000Z","dependencies_parsed_at":"2023-10-12T23:41:58.277Z","dependency_job_id":"24aa9548-3518-4dd9-8917-4f6478e95a9e","html_url":"https://github.com/ComFreek/async-playground","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ComFreek/async-playground","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ComFreek%2Fasync-playground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ComFreek%2Fasync-playground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ComFreek%2Fasync-playground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ComFreek%2Fasync-playground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ComFreek","download_url":"https://codeload.github.com/ComFreek/async-playground/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ComFreek%2Fasync-playground/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278386120,"owners_count":25978109,"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","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["async-generators","asynchronous","asynchronous-programming","generator","modern-javascript","promises","semaphores","typescript"],"created_at":"2025-08-08T12:16:29.532Z","updated_at":"2025-10-04T22:42:00.205Z","avatar_url":"https://github.com/ComFreek.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ComFreek's async generator/Promises playground\n\n[![CI](https://github.com/ComFreek/async-playground/actions/workflows/main.yml/badge.svg)](https://github.com/ComFreek/async-playground/actions/workflows/main.yml)\n[![Coverage Status](https://img.shields.io/coveralls/ComFreek/async-playground.svg)](https://coveralls.io/github/ComFreek/async-playground?branch=master)\n\u0026nbsp; \u0026nbsp; [GitHub Repo](https://github.com/ComFreek/async-playground) | [Documentation](https://comfreek.github.io/async-playground) | [Coverage results](https://comfreek.github.io/async-playground/coverage)\n\nInspired by\n[Exploring ES2018 and ES2019](http://exploringjs.com/es2018-es2019/index.html) by [Dr. Axel Rauschmayer](http://dr-axel.de/), especially the part on asynchronous generators, I wrote some TypeScript classes of well-known concepts.\n\nIt's fun to (re-)explore these concepts, but with Promises and ECMAScript's execution model in mind:\n\n  - `Semaphore`: typical counting semaphore implementation\n    ```typescript\n    const sem = new Semaphore();\n    doSomeIO().then(() =\u003e sem.free());\n    await sem.take();\n    ```\n\n  - `AsyncQueue`: a queue with asynchronous dequeue operation\n    ```typescript\n    const queue = new AsyncQueue\u003cstring\u003e();\n\n    getFile('test.txt').on('line', (line) =\u003e queue.queue(line));\n\n    // Process the lines\n    await queue.dequeue();\n    ```\n\n  - `AsyncLimitedQueue`: a queue where the queue operation is asynchronous as well\n    since it enforces a user-specified limit on the number of entries.\n\n    ```typescript\n    // Only store up to 30 lines at the same time\n    const queue = new AsyncLimitedQueue\u003cstring\u003e(30);\n\n    // queue now returns a promise, which resolves\n    // when the line has been inserted\n    // Assumption: the interface behind getFile() waits for this promise as well to resolve\n    getFile('test.txt').on('line', async (line) =\u003e queue.queue(line));\n\n    // Process the lines\n    await queue.dequeue();\n    ```\n\n  - `CriticalSection`: a non-reentrant critical section.\n\n    ```typescript\n    // see examples/critical-section.ts\n    const queue = new AsyncQueue\u003cnumber\u003e();\n\n    // Sum consecutive (!) lines every 50ms or when an IO event occurred\n    setTimeout(sumConsecutiveNumbers, 50);\n    IO.on('sum', sumConsecutiveNumbers);\n    IO.on('data', (x: number) =\u003e queue.queue(x));\n\n    async function sumConsecutiveNumbers() {\n    \t// Must wrap it in a section, otherwise two \"sumConsecutiveNumbers\"\n    \t// calls from timeout/IO or timeout/timeout or IO/IO may overlap\n    \t// due to the 'await' below!\n    \tawait CriticalSection.for(sumConsecutiveNumbers).do(async () =\u003e {\n    \t\tconst numberOfElementsToSum = 10;\n    \t\tlet sum = 0;\n\n    \t\tfor (let i = 0; i \u003c numberOfElementsToSum; i++) {\n    \t\t\tsum += await queue.dequeue();\n    \t\t}\n    \t\tconsole.log(sum);\n    \t});\n    }\n    ```\n\n## Fully self-contained example\n\nCf. `examples/queue-stdio-lines.ts` and `examples/README.md` on how to run.\n\n```typescript\nimport { IAsyncQueue, AsyncQueue } from '../queue/index';\n\nconst readline = require('readline');\n\nasync function* readInput() {\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false\n\t});\n\n\t// null signals the end of input\n\tconst queue: IAsyncQueue\u003cstring|null\u003e = new AsyncQueue();\n\n\trl.on('line', (line: string) =\u003e queue.queue(line));\n\trl.on('close', () =\u003e queue.queue(null));\n\n\tyield* queue;\n};\n\n(async function() {\n\tfor await (const line of readInput()) {\n\t\tif (line === null) {\n\t\t\tbreak;\n\t\t}\n\t\tconsole.log(line);\n\t}\n})();\n```\n\n## Documentation, Tests, and Coverage\n\nOur GitHub actions [workflow `./github/workflows/main.yml`](.github/workflows/main.yml) builds documentation, runs tests, and analyzes coverage upon every commit to `master`.\n\n**Documentation.** live on \u003chttps://comfreek.github.io/async-playground\u003e and built by `npm run docs`.\n\n**Tests.** run by `npm test`.\n\n**Coverage.**\n\n- `npm run coverage` generates HTML coverage reports and places them into `./coverage` (created if not yet existing).\n\n- `npm run coveralls` generates machine-readable coverage information and publishes them on \u003chttps://coveralls.io/github/ComFreek/async-playground\u003e.\n\n## Contributing \u0026 Licensing\n\nIdeas and code contributions are welcome! Feel free to copy and redistribute code under the terms of the ISC license, see `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomfreek%2Fasync-playground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcomfreek%2Fasync-playground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomfreek%2Fasync-playground/lists"}