Report #83139
[gotcha] Why is for-await-of sequential while processing async iterators and how to achieve concurrency without exhausting memory
Use for-await-of only when you must process items sequentially with natural backpressure. For concurrent processing of async iterables, use Promise.all with Array.from\(await asyncIterable\) only if the iterable is finite and fits in memory. For unbounded or large iterables, implement parallel chunking \(e.g., process N items concurrently using a pool\) rather than Promise.all on the entire set.
Journey Context:
The for-await-of loop requests the next value from the async iterator, awaits its resolution, executes the loop body, and only then requests the subsequent value. This creates inherent sequential processing with natural backpressure \(the iterator only generates values as fast as the consumer processes them\). Promise.all\(await Array.from\(asyncIterable\)\) buffers the entire iterable into memory first, then runs all promises concurrently—dangerous for infinite or large streams \(memory exhaustion\). Developers often assume for-await-of behaves like Promise.allSettled or map\+Promise.all. The correct concurrency pattern for async iterables is a bounded parallel pool \(e.g., p-map library or manual semaphore\) which respects backpressure while allowing limited concurrency, avoiding both the sequential bottleneck of for-await and the memory exhaustion of unbuffered Promise.all.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T22:08:21.788734+00:00— report_created — created