Skip to main content

What is a generator (function*)?

What a generator (function*) is

A generator is a function that can pause its own execution and return intermediate values, then resume from the same spot.

Formally:

function* returns a special object, an iterator, that controls the function's execution.


How to declare a generator

javascript
function* myGenerator() { yield 1; yield 2; yield 3; }

Calling myGenerator() does not run the function's code itself! It returns an iterator, which you need to "advance" manually:

javascript
const gen = myGenerator(); console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: 3, done: false } console.log(gen.next()); // { value: undefined, done: true }

Each yield pauses execution and returns a value.


What yield does

The yield operator:

  1. Pauses the function's execution;
  2. Returns a value outward (to .next());
  3. Lets you pass a value back in on the next .next() call.

Example 1 - a simple sequence:

javascript
function* counter() { yield 1; yield 2; yield 3; } const gen = counter(); console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: 3, done: false } console.log(gen.next()); // { value: undefined, done: true }

Example 2 - pauses between steps

javascript
function* steps() { console.log("Step 1"); yield; console.log("Step 2"); yield; console.log("Step 3"); } const gen = steps(); gen.next(); // "Step 1" gen.next(); // "Step 2" gen.next(); // "Step 3"

Here yield is used without a value, simply as a "pause point".


How to pass a value back into a generator

When you call gen.next(value), that value goes into the generator, at the spot where it was paused by yield.

Example 3 - passing a value back

javascript
function* dialog() { const name = yield "What's your name?"; const age = yield `Hi, ${name}! How old are you?`; yield `You are ${age} years old.`; } const gen = dialog(); console.log(gen.next()); // { value: "What's your name?", done: false } console.log(gen.next("Oleh")); // { value: "Hi, Oleh! How old are you?", done: false } console.log(gen.next(25)); // { value: "You are 25 years old.", done: false } console.log(gen.next()); // { value: undefined, done: true }

Explanation:

  • The first next() starts the generator and returns the first yield.
  • The second next("Oleh") inserts the value "Oleh" at the spot of the first yield.
  • The third next(25) inserts 25 at the spot of the second yield.

Example 4 - a generator with an infinite sequence

javascript
function* infinite() { let i = 0; while (true) { yield i++; } } const gen = infinite(); console.log(gen.next().value); // 0 console.log(gen.next().value); // 1 console.log(gen.next().value); // 2

Generators are ideal for lazy computations, when you need to hand out data "in portions" without building huge arrays.


Controlling a generator

MethodWhat it does
.next(value)Resumes execution and returns the next { value, done }
.return(value)Forcibly ends the generator, returns { value, done: true }
.throw(error)Throws an exception inside the generator, catchable inside try...catch

Example 5 - return() and throw()

javascript
function* process() { try { yield "Step 1"; yield "Step 2"; } catch (e) { console.log("Error:", e.message); } finally { console.log("Generator finished"); } } const gen = process(); console.log(gen.next()); // { value: "Step 1", done: false } console.log(gen.throw(new Error("Something went wrong"))); // Error: Something went wrong // Generator finished

Generators are iterators

A generator automatically implements the iterator interface (next()) and the iterable interface ([Symbol.iterator]).

javascript
function* numbers() { yield 1; yield 2; yield 3; } for (const n of numbers()) { console.log(n); // 1, 2, 3 }

Generators and asynchrony (bonus)

Before async/await existed, generators were used for asynchronous code (via libraries like co).

javascript
function* getData() { const user = yield fetch('/user'); const posts = yield fetch(`/posts?user=${user.id}`); return posts; }

async/await was later built on top of this idea (essentially, "automated generators").


Summary

ConceptDescription
function*Declares a generator
yieldPauses execution and returns a value
.next(value)Resumes execution, passing value in
.return(value)Ends the generator
.throw(error)Throws an exception into the generator
GeneratorAn iterator object that can be paused and resumed

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.