All topics
ES6+advanced

Generator Functions

Functions that can pause and resume execution using yield, producing values lazily one at a time and automatically implementing the iterator protocol.

A generator can pause mid-execution and resume later. yield is where it stops.

A generator function is like a bookmark in a very long book: instead of reading the whole book in one sitting, you read one chapter, hand it over, and put in a bookmark — the book remembers exactly where you stopped.

Key Concepts

1
    function* count() {
      yield 1;
      yield 2;
      yield 3;
    }
2
    const g = count();
    g.next();     // { value: 1, done: false }
    g.next();     // { value: 2, done: false }
    g.next();     // { value: 3, done: false }
    g.next();     // { value: undefined, done: true }
3
Calling it runs nothing. It returns a generator object. The body executes only when next() is called, and pauses again at the next yield.
next()yield
4
Which gives laziness for free.
    function* naturals() { let n = 0; while (true) yield n++; }
5
An infinite loop that does not hang, because it only advances when asked.
6
And it implements the iterator protocol, so a generator works with for...of, spread and destructuring with no extra code.
for...of
7
Two-way communication is the part people miss. next(value) sends a value in, and it becomes the result of the paused yield:
next(value)yield
8
    function* dialogue() {
      const name = yield 'What is your name?';
      const age  = yield `Hello ${name}, how old are you?`;
      return `${name} is ${age}`;
    }
Hello ${name}, how old are you?${name} is ${age}
9
    const d = dialogue();
    d.next();            // asks for the name
    d.next('Asha');      // name = 'Asha'; asks for the age
    d.next(30);          // returns the summary
10
That is what made generators the basis for async control flow before async/await — co-routines that yield promises, with a driver resuming them. async/await is that pattern built into the language.
async/await
11
*yield delegates to another iterable.**
    function* inner() { yield 1; yield 2; }
    function* outer() { yield 0; yield* inner(); yield 3; }
    [...outer()];      // [0, 1, 2, 3]
yield*
12
throw and return control it from outside.
    g.return(99);      // ends it; finally blocks run
    g.throw(err);      // raises inside, at the yield point
throwreturn
13
Where they are genuinely useful today. Traversing a tree lazily, paginated APIs as a flat sequence, generating ids, and state machines. Redux-Saga is built entirely on them.
14
And where not. Ordinary asynchronous code — that is async/await, which is more familiar and reads better.
async/await
15
What the interviewer is probing.1. "What does yield do?" Probing: the mechanism. Stalls: "Returns a value." Moves up: it suspends the function and returns a value, keeping the local state so the next call resumes where it left off.
16
2. "How do you send a value into a generator?" Probing: two-way communication. Stalls: "You cannot." Moves up: next(value) — the argument becomes the result of the paused yield expression.
17
3. "Where are generators genuinely useful?" Probing: practical use. Stalls: "Rarely." *Moves up:* lazy and infinite sequences, custom iterables, and controlled stepping through work — plus they underpin how async/await was originally implemented.
18
*4. "What does yield do?"* Probing: delegation. Stalls: "Yields an array." Moves up:* it delegates to another iterable, flattening its values into this generator's sequence.