Glossary / Async iteration

Async iteration

Async iteration consumes values that arrive over time through the Symbol.asyncIterator protocol. An async iterator’s next() returns a Promise for an iterator-result object. for await...of provides sequential, readable consumption and works with async iterables; it can also consume sync iterables, awaiting yielded Promises where applicable.

Protocol and cleanup

for await (const chunk of response.body) {
  await processChunk(chunk);
}

A ReadableStream body is async iterable in supporting environments. Each loop waits for the next item before continuing, which naturally limits consumer demand to one outstanding iteration step. Breaking or throwing from the loop triggers iterator closing through return() when provided, allowing cleanup. This does not guarantee that an upstream source has no internal buffer or that cancellation propagates unless the source implements it.

Use async iteration when data is a sequence—stream chunks, paginated records, or event feeds. Define error behavior for failures between items, cancellation semantics, and whether partial results remain valid. Do not convert a huge stream into an array unless memory usage is bounded. For parallel processing, use a bounded work queue rather than launching unbounded Promises per chunk.

Interview questions

  1. What protocol does for-await consume? Async iterable via Symbol.asyncIterator, with sync iterable fallback behavior.
  2. What does async iterator next return? A Promise for { value, done }.
  3. How does break support cleanup? It closes the iterator through return() when available.
  4. Does iteration guarantee no buffering? No; upstream sources may buffer.

References