liveBook · Manning

Generator

As explained in Secrets of the JavaScript Ninja, Second Edition

A JavaScript function that can yield values, suspend execution, and later resume with its local state preserved.

A generator is a JavaScript function that produces values on request rather than all at once. It can pause after producing a value, then resume where it left off with its local variables intact. That makes it useful for sequences—and, when paired with promises, for dependent asynchronous work without blocking the browser UI. section 6.2 section 6.4

Declare one with function* and produce a value with yield. Calling it does not run its body immediately; it creates an iterator. Each iterator.next() runs to the next yield and returns an object with value and done properties. A yielded value pauses execution without blocking the main thread. When the function finishes, done is true. A for-of loop requests the yielded values for you. section 6.2 section 6.2.1

IDs without a global counter

function* ids() { let id = 0; while (true) yield ++id; } const iterator = ids(); iterator.next().value; // 1 iterator.next().value; // 2 The counter belongs to this generator's iterator, so unrelated code cannot change it through a global variable. The infinite loop is manageable here: each call advances only to the next yield. section 6.2.2

Generators can do more than send values out. Pass a value to next(value) to make it the result of the yield expression where execution paused; call iterator.throw(error) to raise an exception inside the generator. Use yield* to delegate part of a sequence to another generator. section 6.2.3 section 6.2.1

Listing 6.7. Iterating over a DOM tree with generators
function* DomTraversal(element){
  yield element;
  element = element.firstElementChild;
  while (element) {
    yield* DomTraversal(element);                       #A
    element = element.nextElementSibling;
  }
}

const subTree = document.getElementById("subTree");
for(let element of DomTraversal(subTree)) {                 #B
  assert(element !== null, element.nodeName);               #B
}                                                           #B

Recursive DOM traversal shows why delegation is handy: yield visits the current element, yield* visits each child subtree, and for-of consumes the resulting sequence. section 6.2.2

Under the hood, an iterator moves its generator through a suspended start, execution, a suspended yield, and completion. Its execution context is retained while paused, then reactivated on the next request. For asynchronous tasks, a helper can yield a promise and resume the generator when that promise settles, keeping dependent requests readable without making the requests synchronous. section 6.2.4 section 6.4

How Secrets of the JavaScript Ninja, Second Edition covers it

How deep it goes
Explains syntax, iterator control, two-way communication, state transitions, and retained execution contexts through worked examples.
Examples
Demonstrates yielded strings, a local ID counter, recursive DOM traversal, and dependent JSON requests.
What it assumes
Assumes familiarity with JavaScript functions; introduces generator syntax and iterator behavior before examining execution contexts.
What you can do after
Build it from scratch with function*, yield, next(), and yield* to generate sequences and traverse a DOM tree.
How it connects
Connects generators to iterators, for-of loops, DOM traversal, execution contexts, promises, and asynchronous programming.

Also explained in

Compare how 12 books explain generator →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Secrets of the JavaScript Ninja, Second Edition. The section links point to the parts of the book it draws on.