Skip to main content

JavaScript Generators & Iterators

JavaScript Generator Communication

Written by Published

Values can be sent into a running generator through next, not just read out of it.

A yield expression itself has a value, supplied by the next next() call.

This turns a generator into a genuine two-way conversation.

Example

Example

javascript

function* greeter() {
  const name = yield "What is your name?";
  yield "Hello " + name;
}

const g = greeter();

console.log(g.next().value);
console.log(g.next("Ada").value);

The second call sends Ada in, which becomes the value of the first yield.

Passing Values In

The argument to next() becomes the result of the paused yield.

The very first next() call cannot pass a useful value, since nothing is paused yet.

return() and throw() can also be sent into a generator.

Syntax

Syntax

javascript

const value = yield something;
generator.next(valueToSend);

The first next() only starts the generator running.

The First next Only Starts It

Anything passed to the first call is thrown away.

Example

Example

javascript

function* demo() {
  const first = yield "step one";
  console.log("received: " + first);
}

const g = demo();

g.next("ignored");
g.next("actually received");

The generator had not reached a yield yet on the first call.

A Running Total

Each call both receives and returns a value.

Example

Example

javascript

function* adder() {
  let total = 0;
  while (true) {
    total += yield total;
  }
}

const g = adder();
g.next();

console.log(g.next(5).value);
console.log(g.next(10).value);

The output is 5 then 15.

Ending Early with return

Calling return() on the iterator finishes it immediately.

Example

Example

javascript

function* countUp() {
  yield 1;
  yield 2;
  yield 3;
}

const g = countUp();

console.log(g.next());
console.log(g.return("stopped early"));
console.log(g.next());

Once returned, the generator reports done: true from then on.

Throwing Into a Generator

throw() raises an error at the paused yield, which the generator can catch.

Example

Example

javascript

function* demo() {
  try {
    yield 1;
    yield 2;
  } catch (error) {
    yield "caught: " + error.message;
  }
}

const g = demo();

g.next();

console.log(g.throw(new Error("stop")).value);

The error was handled from inside the generator itself.

An Infinite Loop Is Safe Here

The while (true) above never actually runs forever.

A generator only advances when next() is called, so it pauses at each yield.

Example

Example

javascript

function* forever() {
  let n = 0;
  while (true) {
    yield n;
    n++;
  }
}

const g = forever();

console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);

Nothing runs away, because each call only advances one step.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Generator Communication</title>
</head>
<body>

  <h1>Generator Communication</h1>

  <p id="out"></p>

  <script>
    function* adder() {
      let total = 0;
      while (true) {
        total += yield total;
      }
    }

    const g = adder();
    g.next();

    const after5 = g.next(5).value;
    const after10 = g.next(10).value;

    document.getElementById("out").textContent =
      "After adding 5: " + after5 + ", after adding 10 more: " + after10;
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try one more step:

Call g.next(20) again and see the running total.

Important Points

  • The argument to next() becomes the value of the paused yield.
  • The first next() call only starts the generator.
  • return() ends the generator immediately.
  • throw() raises an error inside the generator, which it can catch.
  • A while (true) loop is safe because yield pauses it.

Conclusion

Generators are not just for producing values; they can receive them too.

This is what makes them useful for coordinating step-by-step work.

The next lesson uses generators to build custom iterable objects.