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
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:
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:
- Pauses the function's execution;
- Returns a value outward (to
.next()); - Lets you pass a value back in on the next
.next()call.
Example 1 - a simple sequence:
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
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
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 firstyield. - The second
next("Oleh")inserts the value"Oleh"at the spot of the firstyield. - The third
next(25)inserts25at the spot of the secondyield.
Example 4 - a generator with an infinite sequence
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); // 2Generators are ideal for lazy computations, when you need to hand out data "in portions" without building huge arrays.
Controlling a generator
| Method | What 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()
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 finishedGenerators are iterators
A generator automatically implements the iterator interface (next()) and the iterable interface ([Symbol.iterator]).
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).
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
| Concept | Description |
|---|---|
function* | Declares a generator |
yield | Pauses 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 |
| Generator | An iterator object that can be paused and resumed |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.