Generators & Iterators
Functions that pause and resume, producing values on demand -- lazy sequences, even infinite ones.
Syntax
function* gen() { yield 1; yield 2; }
for (const v of gen()) {}
obj[Symbol.iterator] = function* () {};The iterator protocol is simple: an object with a next() method that returns { value, done }. Anything implementing it works with for...of, spread, and destructuring.
A generator (function*) is the easy way to build one. yield produces a value and pauses the function, preserving all its local state, until next() is called again.
function* count() {
let n = 0;
while (true) yield n++; // infinite, but lazy -- computed on demand
}
const c = count();
c.next().value; // 0
c.next().value; // 1Why they matter
- Lazy sequences -- generate values only as consumed, so infinite streams are fine.
- Custom iterables -- give your own objects a
[Symbol.iterator]generator and they drop intofor...of. - They can also receive values back through
next(v), the basis of coroutine patterns.
Example
Loading editor…
Press Run to execute the code.
When to use it
- Generate an infinite sequence of unique IDs using a generator so IDs are only computed on demand.
- Implement a lazy paginator that yields one page of API results at a time without loading all pages upfront.
- Use a generator to produce each step of a long-running algorithm so the UI can update between steps.
More examples
Infinite ID sequence generator
Yields an endless sequence of incrementing IDs; each call to next() advances the generator one step.
function* idGenerator(start = 1) {
while (true) yield start++;
}
const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3Finite range generator
A finite generator yields values from start to end with a configurable step, spread into an array.
function* range(start, end, step = 1) {
for (let i = start; i <= end; i += step) yield i;
}
console.log([...range(0, 10, 2)]); // [0, 2, 4, 6, 8, 10]Generator as state machine
Implements a cycling traffic light state machine; each next() call advances to the next state.
function* trafficLight() {
while (true) {
yield "green";
yield "yellow";
yield "red";
}
}
const light = trafficLight();
console.log(light.next().value); // "green"
console.log(light.next().value); // "yellow"
console.log(light.next().value); // "red"
console.log(light.next().value); // "green"
Discussion