{"_id":"@306w/fast-merge-async-iterators","name":"@306w/fast-merge-async-iterators","dist-tags":{"latest":"1.0.7"},"versions":{"1.0.7":{"name":"@306w/fast-merge-async-iterators","version":"1.0.7","description":"Merge AsyncIterables with all corner cases covered.","homepage":"https://github.com/dimikot/fast-merge-async-iterators#readme","author":{"name":"Dimi Kot"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jasperchan/fast-merge-async-iterators.git"},"bugs":{"url":"https://github.com/jasperchan/fast-merge-async-iterators/issues"},"keywords":["AsyncIterator","AsyncIterable","AsyncGenerator","merge","interleave","combine"],"main":"./dist/index.js","typings":"dist/index.d.ts","scripts":{"build":"tsc","dev":"tsc --watch","test":"jest","clean":"rm -rf dist node_modules yarn.lock package-lock.json","deploy":"npm run build && npm test && npm publish"},"devDependencies":{"@types/jest":"^26.0.3","jest":"^26.1.0","ts-jest":"^26.1.1","typescript":"^4.8"},"dependencies":{},"_id":"@306w/fast-merge-async-iterators@1.0.7","gitHead":"9bf62532c092e8d8b72033093f8d19766db9ba9d","_nodeVersion":"20.18.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-Ysg0bioNGxW4D8dM79sUv3vnHXofxiUb9DyOzjiU+HSR4RTYEPRh8q59Ho6rmzH1UXqbbHSsUiSv2SdAvQBnyQ==","shasum":"740eeb383ac1ac56a719e5de1f3ffc512ea59f27","tarball":"https://registry.npmjs.org/@306w/fast-merge-async-iterators/-/fast-merge-async-iterators-1.0.7.tgz","fileCount":7,"unpackedSize":13952,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC/nkYGd97uKK9HEv9kujj7/UGIHuSC1sDalC9rraW3zAiBfTA4Dinf0yCUgBUs/iAul9vuIlE2Us50v6HOixUhilA=="}]},"_npmUser":{"name":"jasperchan","email":"jasperchan@gmail.com"},"directories":{},"maintainers":[{"name":"jasperchan","email":"jasperchan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fast-merge-async-iterators_1.0.7_1728747339457_0.9325928110375237"},"_hasShrinkwrap":false}},"time":{"created":"2024-10-12T15:35:39.391Z","1.0.7":"2024-10-12T15:35:39.643Z","modified":"2024-10-12T15:35:39.894Z"},"maintainers":[{"name":"jasperchan","email":"jasperchan@gmail.com"}],"description":"Merge AsyncIterables with all corner cases covered.","homepage":"https://github.com/dimikot/fast-merge-async-iterators#readme","keywords":["AsyncIterator","AsyncIterable","AsyncGenerator","merge","interleave","combine"],"repository":{"type":"git","url":"git+https://github.com/jasperchan/fast-merge-async-iterators.git"},"author":{"name":"Dimi Kot"},"bugs":{"url":"https://github.com/jasperchan/fast-merge-async-iterators/issues"},"license":"MIT","readme":"# fast-merge-async-iterators: merge AsyncIterables with all corner cases covered\n\nThe idea is to build a ES2018+ compatible module which _really_ covers all the\nfeatures of AsyncIterator, AsyncIterable, AsyncGenerator and <a\nhref=\"https://stackoverflow.com/questions/50585456/how-can-i-interleave-merge-async-iterables\">doesn't\nthrow the baby out with the bathwater</a>.\n\n```ts\nasync function* gen1() { ... yield ... }\nasync function* gen2() { ... yield ... }\nasync function* gen3() { ... yield ... }\n...\nfor await (merge(gen1(), gen2(), gen3())) { ... }\n...\nfor await (merge(\"iters-close-wait\", gen1(), gen2(), gen3())) { ... }\n```\n\n- Interleaves the values yielded by the inner AsyncIterables as soon as they\n  arrive.\n- Supports exceptions propagation down the stack: if an inner iterator throws,\n  then all other iterators will be closed (with or without waiting), and then\n  the exception will be delivered to the caller.\n- Works fast and with no <a href=\"https://github.com/nodejs/node/issues/17469\">memory leak in Promise.race()</a>.\n- Closes merging iterators correctly once the caller stops iterating the merged\n  iterator: calls `.return()` for them which effectively triggers all their\n  `finally {}` blocks.\n\n<a href=\"https://imgflip.com/i/4d7gwx\"><img src=\"https://i.imgflip.com/4d7gwx.jpg\" title=\"made at imgflip.com\"/></a>\n\n## Added In The Fork\n\n- First argument can be an options object:\n\n```ts\ninterface MergeOptions {\n  mode?: Mode;\n  /**\n   * Maximum number of concurrent iterators to read from. Unset or 0 means Infinity. Default is 0.\n   */\n  concurrency?: number;\n}\n```\n\n## Usage Example\n\n```ts\nimport merge from \"fast-merge-async-iterators\";\n\nasync function* generator(name: string, dt: number) {\n  try {\n    for (let i = 0; ; i++) {\n      console.log(`${name} yielded ${i}`);\n      yield `${name}: ${i}`;\n      await new Promise((resolve) => setTimeout(resolve, dt));\n    }\n  } finally {\n    console.log(`Closing ${name} (doing some cleanup)`);\n    await new Promise((resolve) => setTimeout(resolve, 100));\n  }\n}\n\nasync function* caller() {\n  // JS does a good job of propagating iterator close operation (i.e.\n  // calling `.return()` an iterator is used in `yield*` or `for await`).\n  yield* merge(\"iters-close-wait\", generator(\"A\", 222), generator(\"B\", 555));\n  // Available modes:\n  // - \"iters-noclose\" (does not call inner iterators' `return` method)\n  // - \"iters-close-nowait\" (calls `return`, but doesn't await nor throw)\n  // - \"iters-close-wait\" (calls `return` and awaits for inners to finish)\n}\n\n(async () => {\n  for await (const message of caller()) {\n    if (message.includes(\"2\")) {\n      // This `break` closes the merged iterator, and the signal is\n      // propagated to all inner iterators.\n      break;\n    }\n    console.log(`Received from ${message}`);\n  }\n  console.log(\"Finishing\");\n})();\n```\n\nResult:\n\n```\nA yielded 0\nB yielded 0\nReceived from A: 0\nReceived from B: 0\nA yielded 1\nReceived from A: 1\nA yielded 2\nClosing A (doing some cleanup)\nB yielded 1\nClosing B (doing some cleanup)\nFinishing\n```\n\n## Inspired by\n\nThe alternative libraries mentioned below have one or more flaws. Mostly it's\nabout inability to close the inner iterators once the merged iterator is closed,\nhaving a memory leak when one iterator finishes early, and about having an\novercomplicated/slow code.\n\n- https://github.com/reconbot/streaming-iterables/blob/master/lib/parallel-merge.ts\n- https://github.com/fraxken/combine-async-iterators/blob/master/index.js\n- https://github.com/vadzim/mergeiterator/blob/master/src/mergeiterator.ts\n- https://github.com/hesher/mergen/blob/master/mergen.js\n- https://github.com/ReactiveX/IxJS/blob/master/src/asynciterable/merge.ts\n- https://github.com/laggingreflex/merge-async-iterators/blob/master/index.js\n\nSituation: There are 6 different libraries to merge AsyncIterables with different bugs and corner cases.\n\nCueball: 6?! Ridiculous! We need to develop one universal library that covers everyone's use cases.\n\nPonytail: Yeah!\n\n(Soon) Situation: There are 7 different libraries to merge AsyncIterables.\n","readmeFilename":"README.md"}