Back to Blog
Patterns2026-04-05

JavaScript Generators: Practical Patterns Beyond the Basics

Explore practical generator patterns including lazy evaluation, infinite sequences, async iteration, and state machines.

Generators Recap

Generators are functions that can pause and resume execution, yielding values one at a time. They're declared with \function*\ and use the \yield\ keyword. While many tutorials cover the basics, generators shine in practical scenarios that go far beyond simple iteration.

Lazy Evaluation Pipelines

Generators let you build data processing pipelines that only compute values as needed — no intermediate arrays, no wasted memory.

``javascript function* range(start, end) { for (let i = start; i < end; i++) yield i; }

function* filter(iterable, predicate) { for (const item of iterable) { if (predicate(item)) yield item; } }

function* map(iterable, transform) { for (const item of iterable) { yield transform(item); } }

function* take(iterable, count) { let i = 0; for (const item of iterable) { if (i++ >= count) return; yield item; } }

// Process 1 million items lazily — only 5 items actually computed const result = take( map( filter(range(0, 1_000_000), (n) => n % 3 === 0), (n) => n * n ), 5 );

console.log([...result]); // [0, 9, 36, 81, 144] `

Paginated API Fetching

Generators pair beautifully with async iteration to handle paginated APIs without loading everything into memory.

`javascript async function* fetchPages(baseUrl) { let page = 1; while (true) { const response = await fetch(\\${baseUrl}?page=\${page}\); const data = await response.json();

if (data.items.length === 0) return;

yield* data.items; page++; } }

// Usage — process items one by one across all pages for await (const item of fetchPages('/api/products')) { processItem(item); if (shouldStop(item)) break; // Can stop early! } `

State Machine with Generators

Generators naturally model state machines because they maintain internal state between yields.

`javascript function* trafficLight() { while (true) { yield { color: 'green', duration: 30 }; yield { color: 'yellow', duration: 5 }; yield { color: 'red', duration: 20 }; } }

const light = trafficLight(); console.log(light.next().value); // { color: 'green', duration: 30 } console.log(light.next().value); // { color: 'yellow', duration: 5 } console.log(light.next().value); // { color: 'red', duration: 20 } console.log(light.next().value); // { color: 'green', duration: 30 } — cycles! ``

Generators are an underutilized feature that elegantly solve problems involving sequences, pagination, state machines, and lazy computation. They make your code more memory-efficient and often more readable than callback-based alternatives.