Iterators and Generators
Generators are functions that can pause and resume. They make it easy to produce values one at a time — even endless streams.
On this page · 5 min · Advanced
On this page
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Advanced
- Updated
- Oct 27, 2026
Related tutorials
Learning objectives#
- Write generator functions with function* and yield
- Step through values with next()
- Create lazy, infinite sequences
- Make objects iterable with Symbol.iterator
Explanation#
An iterator is any object with a next() method that returns { value, done }. for…of and spread use iterators automatically.
A generator (function*) returns an iterator. Each yield hands out one value and pauses until the next request.
Because values are produced on demand, generators can describe infinite sequences without running forever.
Adding a [Symbol.iterator] generator method to an object makes it work with for…of and spread.
Code example: Countdowns, IDs and ranges#
function* countdown(from) {
while (from > 0) yield from--;
return 'Lift off!';
}
const it = countdown(3);
console.log(it.next());
console.log([...countdown(3)]);
function* ids() {
let id = 1;
while (true) yield `user-${id++}`;
}
const gen = ids();
console.log(gen.next().value, gen.next().value);
const range = {
from: 1, to: 4,
*[Symbol.iterator]() { for (let i = this.from; i <= this.to; i++) yield i; },
};
console.log([...range]);
{ value: 3, done: false }
[ 3, 2, 1 ]
user-1 user-2
[ 1, 2, 3, 4 ]Step-by-step explanation#
- The first next() runs until the first yield and returns 3.
- Spreading collects all yielded values; the return value is not included.
- ids() is infinite, but only two values are requested, so it never hangs.
- range becomes iterable thanks to its Symbol.iterator generator.
Real-world use case#
Paging through API results one page at a time, generating unique IDs, or processing very large data sets without loading everything into memory.
Common mistakes#
[...ids()] never finishes. Only take as many values as you need.
yield only works inside function*.
Best practices#
- Use generators for lazy or infinite sequences
- Use for…of to consume iterators
- Use async generators (async function*) for streams of async data
- Keep generator logic simple
Remember this#
function* = a function with a pause button.
yield = “here’s one value, wake me when you need the next”.
next() returns { value, done }.
Practice exercise#
Your task: Write a generator evens() that yields 0, 2, 4, … forever, and log the first five values.
Show solution
function* evens() { let n = 0; while (true) { yield n; n += 2; } }
const g = evens();
for (let i = 0; i < 5; i++) console.log(g.next().value); // 0 2 4 6 8
Mini quiz#
What does the second next() return?
function* g() { yield 'a'; }
const it = g();
it.next();
console.log(it.next());
Want more? Practise all JavaScript MCQs · JavaScript interview questions
My notes#
Saved in this browser.