Generators & Iterators Theory
Generators are pause-and-resume functions that produce iterator objects, enabling lazy evaluation, controlled sequencing, and two-way communication through next calls.
What it is
A generator function is declared with function* and returns an iterator when invoked. The function body does not run immediately on creation.
Each yield pauses execution and emits a value. Subsequent next calls resume from the exact paused point with preserved local state.
Generators unify iterable protocols and stateful control flow, making them useful for custom iteration, step-by-step workflows, and stream-like data consumption.
Interview framing: define Generators & Iterators in one sentence, then explain one concrete runtime behavior and one common pitfall with a short code example.
How it works
- Step 1: calling a generator function returns an iterator object.
- Step 2: iterator.next starts execution until the first yield or return.
- Step 3: each next call resumes execution and can pass data back into the generator.
- Step 4: when done is true, iteration completes and no further yielded values are produced.
Common mistakes
Expecting generator body to execute on function call
Generator functions are lazy. Execution begins only when next is called on the returned iterator.
Fix: Always reason about generators as state machines driven by iterator calls.
Reusing exhausted iterators
Once an iterator finishes, additional next calls stay done and do not restart the sequence.
Fix: Create a new iterator by calling the generator function again when a fresh run is needed.
Ignoring error and completion channels
Generators support throw and return, and failing to handle these channels can break control flow assumptions.
Fix: Design generator consumers to account for done state and possible thrown errors.
Interview questions
Common interview prompts with concise model answers.
Are generators asynchronous by default?
No. Standard generators are synchronous. Async generators use async function* and integrate with for await...of.
function* ids() {
yield 1;
yield 2;
}
const it = ids();
console.log(it.next()); // { value: 1, done: false }How do generators relate to iterables?
Generator iterators implement the iterator protocol and are also iterable, so they work directly with for...of and spread in many cases.
Can next pass data into a generator?
Yes. The value passed to next becomes the result of the suspended yield expression inside the generator.
When should I choose generators over arrays?
Use generators for lazy sequences, large or infinite streams, and scenarios where you need incremental processing without eager allocation.
Related concepts
Continue with these concepts to strengthen your mental model.