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.