Generator Functions

Difficulty: Advanced

Question

What are generator functions in JavaScript? What are their use cases?

Answer

Generator functions (function*) return a Generator object that implements the iterator protocol. They can pause execution at each yield expression and resume from that point.

How they work: - Calling a generator function returns a generator object (does not execute the body) - Each call to .next() runs the body until the next yield - .next() returns { value, done } - yield* delegates to another iterable

Use cases: lazy infinite sequences, custom iterables, async control flow, cooperative multitasking, and data pipeline transformations.

Code examples

Basic Generator and Infinite Sequence

function* counter(start = 0) {
  while (true) {
    yield start++;
  }
}

const gen = counter(1);
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3

function take(gen, n) {
  const result = [];
  for (const val of gen) {
    result.push(val);
    if (result.length >= n) break;
  }
  return result;
}

console.log(take(counter(1), 5));

Generators produce values lazily - the infinite loop never runs out of control because execution pauses at each yield.

Two-way Communication and yield*

function* dialog() {
  const name = yield 'What is your name?';
  const age = yield `Hello ${name}! How old are you?`;
  yield `${name} is ${age} years old.`;
}

const d = dialog();
console.log(d.next().value);
console.log(d.next('Alice').value);
console.log(d.next(30).value);

function* flatten(arr) {
  for (const item of arr) {
    if (Array.isArray(item)) yield* flatten(item);
    else yield item;
  }
}

console.log([...flatten([1, [2, [3, 4]], 5])]);

Passing a value to next() sends it back as the result of the yield expression. yield* delegates to another generator or iterable.

Key points

Concepts covered

function*, yield, Iterator Protocol, Lazy Evaluation