JavaScript Generators: Writing Iterators With yield

JavaScript Generators: Writing Iterators With yield

JavaScript generators explained: write lazy iterators with yield, handle infinite sequences, and skip the protocol boilerplate.

Martin Ferret

Martin Ferret

July 21, 2026

JavaScript generators have existed since ES2015, yet many developers still treat yield as an exotic feature. It solves a common problem: producing values on demand, one at a time, without building the whole sequence in memory. A generator lets you write an iterator with ordinary control flow, pausing and resuming a function like a paused video.

The Problem They Solve

Writing a custom iterator by hand means implementing the protocol yourself: an object with a next() method returning { value, done }, with state threaded through closures.

      `function range(start, end) {
  let current = start;
  return {
    Symbol.iterator { return this; },
    next() {
      return current < end
        ? { value: current++, done: false }
        : { value: undefined, done: true };
    },
  };
}`

    

A generator expresses the same logic as the control flow it actually is:

      `function* range(start, end) {
  for (let i = start; i < end; i++) yield i;
}`

    

No next, no done, no protocol object. The engine writes that for you.

How It Works

Declared with function*. Calling it does not run the body: it returns a generator object. Execution advances only when you pull a value.

      `function* letters() {
  yield 'a';
  yield 'b';
}

    

const g = letters(); g.next(); // { value: 'a', done: false } g.next(); // { value: 'b', done: false } g.next(); // { value: undefined, done: true }`

Each next() runs to the next yield, returns that value, and freezes. Locals and position are preserved between calls.

Infinite Sequences

Because the function is paused rather than finished, you can write sequences that never end:

      `function* naturals() {
  let i = 1;
  while (true) yield i++;
}`

    

The while (true) is safe: it only advances one step per next().

yield* and next(value)

yield* delegates to another iterable, forwarding all its values:

      `function* outer() {
  yield 0;
  yield* [1, 2];
  yield 3;
}
[...outer()]; // [0, 1, 2, 3]`

    

The argument passed to next becomes the result of the yield where the generator is paused, making it a two-way channel. Note: the first next() argument is ignored, since no yield is waiting yet.

      `function* ask() {
  const name = yield 'name?';
  return `hi ${name}`;
}
const a = ask();
a.next().value;      // 'name?'
a.next('Ada').value; // 'hi Ada'`

    

Both Iterator and Iterable

A generator returns itself from [Symbol.iterator], so it drops into for...of, spread, and destructuring with no conversion. It also chains with the new iterator helpers:

      `naturals().filter((x) => x % 2 === 0).take(3).toArray(); // [2, 4, 6]`

    

An infinite source, processed safely, because take(3) stops the pipeline.

What to Watch Out For

Single-use. Once exhausted, a generator stays exhausted. Call the function again for a fresh one.

for...of discards the return value. A return x sets { value: x, done: true }, but loops and spread stop at done and never see it.

Arrow functions cannot be generators. Always function* or a *method().

Spreading an infinite generator hangs. Bound it with take before draining it.

Where It Runs Today

Generators are Baseline widely available. They shipped with ES2015 and have worked in every major engine for close to a decade: Chrome 39+, Firefox 26+, Safari 10+, Node 4+. TypeScript types them fully. Async generators (async function*) extend the same idea to asynchronous streams since ES2018.

What to Take Away

Generators add no new power, a hand-written iterator can do the same. What yield changes is how much machinery stands between you and the sequence. Manual done flags become ordinary control flow, infinite sequences become a safe while (true), and composition becomes one yield*. For custom iteration, lazy sequences, tree walks, or ID factories, reaching for a generator is a clean win.

More certificates.dev articles

Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.