| | type Gen<T, TReturn> = AsyncGenerator<T, TReturn, undefined>; |
| |
|
| | type GenPromiseMap<T, TReturn> = Map< |
| | Gen<T, TReturn>, |
| | Promise<{ gen: Gen<T, TReturn> } & IteratorResult<T, TReturn>> |
| | >; |
| |
|
| | |
| | export async function* mergeAsyncGenerators<T, TReturn>( |
| | generators: Gen<T, TReturn>[] |
| | ): Gen<T, TReturn[]> { |
| | const promises: GenPromiseMap<T, TReturn> = new Map(); |
| | const results: Map<Gen<T, TReturn>, TReturn> = new Map(); |
| |
|
| | for (const gen of generators) { |
| | promises.set( |
| | gen, |
| | gen.next().then((result) => ({ gen, ...result })) |
| | ); |
| | } |
| |
|
| | while (promises.size) { |
| | const { gen, value, done } = await Promise.race(promises.values()); |
| | if (done) { |
| | results.set(gen, value as TReturn); |
| | promises.delete(gen); |
| | } else { |
| | promises.set( |
| | gen, |
| | gen.next().then((result) => ({ gen, ...result })) |
| | ); |
| | yield value as T; |
| | } |
| | } |
| |
|
| | const orderedResults = generators.map((gen) => results.get(gen) as TReturn); |
| | return orderedResults; |
| | } |
| |
|