0Pricing
Node.js Backend Development Bootcamp · Lesson

Async Iterators and for-await-of Over Streams

Consume Readable streams ergonomically with async iteration and convert between streams and async generators.

Why Async Iteration Over Streams

Node.js Readable streams emit chunks over time. The classic way to consume them is by wiring up 'data', 'end', and 'error' event listeners. That works, but it scatters your logic across callbacks and makes pausing, resuming, and error handling awkward.

Since Node 10, every Readable stream is an async iterable. That means you can consume it with a plain for await...of loop:

  • Sequential chunk processing, written top to bottom
  • Automatic backpressure — the loop pulls one chunk at a time
  • try/catch works for stream errors

This lesson shows how to consume, transform, and produce streams ergonomically with async iteration.

for-await-of Basics

A for await...of loop awaits each value produced by an async iterator before moving to the next. When applied to a Readable stream, each iteration yields one chunk (a Buffer by default, or a string if the stream encoding is set).

Here we read this script's own source file line-by-chunk. The loop body runs once per chunk and the loop naturally ends when the stream finishes:

import { createReadStream } from 'node:fs';
import { fileURLToPath } from 'node:url';

const self = fileURLToPath(import.meta.url);
const stream = createReadStream(self, { encoding: 'utf8' });

let chunks = 0;
let bytes = 0;
for await (const chunk of stream) {
  chunks++;
  bytes += chunk.length;
}
console.log('chunks:', chunks, 'chars:', bytes);

All lessons in this course

  1. Readable, Writable, Duplex & Transform Stream Internals
  2. Implementing Custom Transform Streams with _transform and _flush
  3. Backpressure, pipe() and the pipeline() Utility
  4. Async Iterators and for-await-of Over Streams
← Back to Node.js Backend Development Bootcamp