* Merge multiple async iterables by yielding values in temporal order. * @param {...(AsyncIterable |object)} args * @returns {AsyncIterable }
(...args)
| 393 | * @returns {AsyncIterable<Uint8Array[]>} |
| 394 | */ |
| 395 | function merge(...args) { |
| 396 | let sources; |
| 397 | let options; |
| 398 | |
| 399 | if (args.length > 0 && isMergeOptions(args[args.length - 1])) { |
| 400 | options = args[args.length - 1]; |
| 401 | sources = ArrayPrototypeSlice(args, 0, -1); |
| 402 | } else { |
| 403 | sources = args; |
| 404 | } |
| 405 | |
| 406 | if (options?.signal !== undefined) { |
| 407 | validateAbortSignal(options.signal, 'options.signal'); |
| 408 | } |
| 409 | |
| 410 | // Normalize each source via from() |
| 411 | const normalized = ArrayPrototypeMap(sources, (source) => from(source)); |
| 412 | |
| 413 | return { |
| 414 | __proto__: null, |
| 415 | async *[SymbolAsyncIterator]() { |
| 416 | const signal = options?.signal; |
| 417 | |
| 418 | signal?.throwIfAborted(); |
| 419 | |
| 420 | if (normalized.length === 0) return; |
| 421 | |
| 422 | if (normalized.length === 1) { |
| 423 | for await (const batch of normalized[0]) { |
| 424 | signal?.throwIfAborted(); |
| 425 | yield batch; |
| 426 | } |
| 427 | return; |
| 428 | } |
| 429 | |
| 430 | // Multiple sources - use a ready queue so that batches that settle |
| 431 | // between consumer pulls are drained synchronously without an extra |
| 432 | // async tick per batch. Each source has at most one pending .next() |
| 433 | // at a time. Every batch from every source is preserved. |
| 434 | const ready = []; |
| 435 | let activeCount = normalized.length; |
| 436 | let waitResolve = null; |
| 437 | |
| 438 | // Called when a source's .next() settles. Pushes the result into |
| 439 | // the ready queue and wakes the consumer if it's waiting. |
| 440 | const onSettled = (iterator, result) => { |
| 441 | if (result.done) { |
| 442 | activeCount--; |
| 443 | } else { |
| 444 | ArrayPrototypePush(ready, result.value); |
| 445 | // Immediately request the next value from this source |
| 446 | // (at most one pending .next() per source) |
| 447 | PromisePrototypeThen( |
| 448 | iterator.next(), |
| 449 | (r) => onSettled(iterator, r), |
| 450 | (err) => { |
| 451 | ArrayPrototypePush(ready, { __proto__: null, error: err }); |
| 452 | if (waitResolve) { |
nothing calls this directly
no test coverage detected