method StreamClass.prototype.mapConcurrent
Private
StreamClass.prototype.mapConcurrent<R>(
fn: (
value: T,
signal: AbortSignal
) => R | PromiseLike<R>
,
options?: { maxConcurrency?: number; timeoutMs?: number; ordered?: boolean; }
): StreamClass<
Exclude<R, AnyFailure>,
E | Extract<R, AnyFailure> | AnyFailure
>

StreamClass.asyncStream as a stage: the same bounded fan-out, usable in the middle of a pipeline instead of only at the start of one.

const rows = await Stream.from([1, 2, 3, 4])
  .filter((n) => n % 2 === 0)
  .mapConcurrent((n) => n * 10, { maxConcurrency: 2 })
  .collect();
rows; // [20, 40]

Why concurrency is a stage rather than a .limit(n) you append. The obvious API is TC39's — .map(fetch).limit(5) — and it cannot work on top of async generators. A generator has one suspended body, so it has exactly one resume point, and it serializes .next() no matter how many calls are in flight. Measured: a downstream limiter aggressively keeping three .next() calls outstanding over a generator-backed map of six 40ms elements still took 242ms at peak concurrency 1 — identical to serial. Nothing downstream can parallelise work that upstream has already awaited.

So the stage that performs the async work is the only place that can introduce concurrency, which is what this is. It is also why TC39's helpers are still unshipped: to make .limit composable they must first respecify the helpers as something other than async generators.

Type Parameters

Parameters

fn: (
value: T,
signal: AbortSignal
) => R | PromiseLike<R>
optional
options: { maxConcurrency?: number; timeoutMs?: number; ordered?: boolean; }

Return Type

StreamClass<
Exclude<R, AnyFailure>,
E | Extract<R, AnyFailure> | AnyFailure
>

Usage

import { StreamClass } from "lib/stream/stream.ts";