Iterators and Generators
Iterators and Generators in JavaScript
Custom iteration protocols, lazy evaluation, and pausing function execution with generators.
The Book Bookmark and the Automated Pez Dispenser
Iterators and Generators standardize how collections are traversed and enable lazy data streams that produce values on demand rather than allocating memory up front.
The Iterable Protocol
An object is iterable if it implements the `[Symbol.iterator]` method, which returns an iterator object (used by `for...of`, spread `[...]`, and `Array.from()`).
The Iterator Protocol
An object is an iterator if it implements a `.next()` method returning `{ value: any, done: boolean }`.
Generators (function* and yield)
Generators are special functions denoted with `function*`. Calling a generator returns a Generator object without running its body. Calling `.next()` executes code until hitting the next `yield` keyword, where execution freezes.
Two-Way Message Passing
Passing an argument into `generator.next(val)` replaces the result of the paused `yield` expression inside the generator body, allowing bi-directional communication.
Creating a custom Fibonacci generator producing values lazily on demand:
// Infinite lazy Fibonacci generator
function* fibonacciGenerator() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const fib = fibonacciGenerator();
// Pulling values on demand without memory explosion
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5
// Consuming first 4 numbers with a custom helper
function take(iterable, count) {
const result = [];
for (const val of iterable) {
result.push(val);
if (result.length >= count) break;
}
return result;
}
console.log("Next 4 Fibonacci:", take(fib, 4));
1
1
2
3
5
Next 4 Fibonacci: [ 8, 13, 21, 34 ]
Exhausted Generators Cannot Be Rewound
The Risk: Once a generator yields `{ done: true }`, calling `.next()` repeatedly continues returning `{ value: undefined, done: true }`.
The Fix: To iterate again, invoke the generator function to instantiate a fresh generator instance.
- ✓ Iterables implement `[Symbol.iterator]()`.
- ✓ Iterators implement `.next() -> { value, done }`.
- ✓ Generators use `function*` syntax and pause at `yield`.
- ✓ Generators enable memory-efficient lazy computation of large or infinite streams.
- ✓ Passing values to `.next(arg)` sends data into the generator.