Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Iterators and Generators  ›  Lesson

Generator Functions

Generator Functions 12 minA generator function, declared with function*, runs only up to its next yield each time .next() is called, pausing there with its local state intact, and is itself iterable, so it can be used directly in for...of or spread.

Generator Functions

In short: a generator function, written function* name() { ... }, doesn't run when you call it — calling it just creates a generator object, paused before its first line. Each call to .next() resumes it and runs code up to the next yield, then pauses again right there, with every local variable exactly as it was. That returned { value, done } follows the same shape as any other iterator — because a generator is an iterator, which means it also works directly in for...of and the spread operator.

A function body: console.log("starting"); yield "Blue Hour"; then PAUSED — waiting here, connected by it.next() to a second block: console.log("resumed once"); yield "Red Dawn"; // pauses again — each .next() runs code until the next yield, then freezes there, nothing after it runs yet

Step through a generator one yield at a time

Calling a generator function produces the generator object immediately, but none of its body runs until the first .next():

javascript

Nothing prints until the first it.next() — that's when "starting" finally runs, up to yield "Blue Hour", where execution freezes and { value: "Blue Hour", done: false } is returned. The second next() picks up exactly where it left off, runs "resumed once", reaches the next yield, and pauses again. The third next() runs the last line and finishes, giving { value: undefined, done: true } — there's no more yield left to stop at.

Use a generator directly in for...of

A generator's built-in [Symbol.iterator] returns itself, so it plugs straight into anything that consumes an iterable:

javascript

for...of calls .next() on the generator automatically, printing each yielded title and stopping once done is true — no manual iterator protocol needed, the same way it works for arrays. [...songTitles()] collects every yielded value into a real array, ["Blue Hour", "Red Dawn"].

Quick practice

quick drill

What happens when you call a generator function, like songTitles(), without calling .next()?

quick drill

What does each call to .next() do on a generator?

quick drill

After the last yield has been reached and passed, what does the next .next() call return?

quick drill

Why does for (const title of songTitles()) { ... } work without calling .next() manually?

quick drill

What prints first when running function* g() { console.log("A"); yield 1; } const it = g(); console.log("B"); it.next();?

🎯 Your turn

Trace function* songTitles() { console.log("starting"); yield "Blue Hour"; console.log("resumed once"); yield "Red Dawn"; console.log("resumed twice"); } const it = songTitles(); it.next(); it.next(); it.next(); line by line, explaining what prints and when, and why calling songTitles() alone doesn't print "starting" immediately.

Write your explanation and submit it — there's no code to run here, just your reasoning.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainTrace the pauses

Trace function* songTitles() { console.log("starting"); yield "Blue Hour"; console.log("resumed once"); yield "Red Dawn"; console.log("resumed twice"); } const it = songTitles(); it.next(); it.next(); it.next(); line by line, explaining what prints and when, and why calling songTitles() alone doesn't print "starting" immediately.