DevAcademy
LearnJavaScriptGenerators and Iterators
AdvancedJavaScript

Generators and Iterators

Learn the iterator and iterable protocols that power for...of loops, and how generator functions with function* and yield let you build custom, pausable sequences with ease.

Reading Time

20 min

Lesson

Lesson 42 of 48

The Iterator Protocol

The iterator protocol is a simple contract: an object is an iterator if it has a next() method, and calling that method returns an object shaped like { value, done }. value is the next item in the sequence, and done is a boolean that becomes true once there's nothing left to produce. That's the entire contract — no special class or built-in type is required, just an object with the right method shape.

A Manual Iterator

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

The Iterable Protocol

The iterable protocol builds on top of the iterator protocol: an object is iterable if it has a method at the special key Symbol.iterator, and calling that method returns an iterator (an object matching the shape above). Being iterable is what makes an object usable with for...of, the spread operator (...), destructuring, and Array.from().

What's Iterable Out of the Box

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Making Your Own Object Iterable

You can make any object work with for...of by giving it a Symbol.iterator method that returns an iterator. This is exactly how you would implement a custom collection type — a linked list, a range, or a queue — that you want to feel like a first-class part of the language.

A Custom Iterable Object

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Generator Functions

Writing the iterator protocol by hand every time is tedious. A generator function — declared with function* and using yield inside — does the same job with far less boilerplate. Calling a generator function does not run its body immediately; instead it returns a generator object, which is both an iterator and an iterable. Each call to .next() runs the function until it hits a yield, pauses there, and returns that yielded value.

A Basic Generator

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Pausing and Resuming Execution

The defining feature of a generator is that execution truly pauses at each yield and picks back up exactly where it left off on the next call to .next() — including any local variables and loop state. This makes generators well suited for representing sequences that are computed lazily, one step at a time, rather than all at once.

Execution Order with Multiple Yields

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Passing Values Into a Generator

yield is a two-way street: not only does it produce a value out of the generator, but whatever you pass to the next .next() call becomes the result of that yield expression inside the generator body. This lets a generator receive input from the outside world at each pause point, not just emit values.

Sending Values Back Into a Generator

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Practical Example: An Infinite Sequence

Generators are a natural fit for infinite sequences, since values are only computed as they are requested. You can safely define a generator that never runs out, and simply stop pulling values from it whenever you have enough.

An Infinite Generator with a Manual Stopping Point

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Iterator vs. Iterable vs. Generator

ConceptDefinition
IteratorAn object with a next() method returning { value, done }
IterableAn object with a Symbol.iterator method that returns an iterator
GeneratorA function* whose calls return an object that is both an iterator and an iterable

Generators Simplify Custom Iterables

If you find yourself hand-writing a Symbol.iterator method with a manual next() implementation, consider replacing it with a generator function instead — the same for...of behavior, expressed with a plain loop and yield, is usually far easier to read and maintain.

Be Careful with Infinite Generators

An infinite generator used directly in a for...of loop without a break, or spread with the ... operator, or converted with Array.from(), will never finish and will hang or exhaust memory. Always pair an infinite generator with an explicit stopping condition.

Interview Questions

Quick Quiz

1. What must an object have to satisfy the iterator protocol?

2. What makes an object usable with for...of?

3. What keyword pauses execution inside a generator function?

4. What happens when you call a generator function?

5. What happens to the value passed to gen.next(value)?