Q31 of 40 · JavaScript

What are generator functions in JavaScript, and when are they useful?

JavaScriptMidjavascriptgeneratorsiteratorses6lazy-evaluation

Short answer

Short answer: Generator functions (`function*`) return an iterator that can pause at `yield` expressions and resume on `.next()`. They produce values lazily — useful for infinite sequences, custom iterables, async control flow (before async/await), and test data factories that generate unique values on demand.

Detail

A generator function is declared with function* and uses yield to produce values one at a time. The function body is not executed until .next() is called on the returned iterator.

How it works: Each .next() call resumes execution from the last yield until the next yield or return. The return value of .next() is { value, done }. When the function returns (or falls off the end), done becomes true.

Lazy evaluation: Generators compute values only when requested. A generator can produce an infinite sequence without exhausting memory — values are produced on demand.

Pass values in: .next(value) resumes the generator and the yield expression evaluates to value. This bidirectional communication was used by co and redux-saga before async/await.

as Iterables: Generator functions implement the iterable protocol — you can spread them, use for...of, and destructure them.

In testing: Generators are useful for creating unique ID factories, sequential test data, and lazy fixture sequences.

// EXAMPLE

// Basic generator
function* count(start = 1) {
  while (true) {
    yield start++;
  }
}
const counter = count();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2

// Finite sequence — for...of
function* range(start, end) {
  for (let i = start; i <= end; i++) yield i;
}
console.log([...range(1, 5)]); // [1, 2, 3, 4, 5]

// Test ID factory
function* idGenerator(prefix = "user") {
  let n = 1;
  while (true) yield `${prefix}-${n++}`;
}
const nextId = idGenerator("order");
const id1 = nextId.next().value; // "order-1"
const id2 = nextId.next().value; // "order-2"

// WHAT INTERVIEWERS LOOK FOR

The pause-and-resume model, `{ value, done }` return shape, lazy evaluation benefits. Connecting generators to the iterable protocol. Bonus: mentioning redux-saga or historical async control flow use, or test ID factories.

// COMMON PITFALL

Forgetting that a generator function call returns an iterator object — calling `generatorFn()` alone produces no output. You must call `.next()` on the returned iterator to start execution.