JavaScript Generators and Iterators
Produce values lazily with iterators and pausable generator functions
Overview
An iterator is any object with a next() method that returns { value, done }, and it becomes iterable by implementing Symbol.iterator. Generators (function*) are a concise way to build iterators, pausing at each yield and resuming on the next call. Together they enable lazy, on-demand sequences that can even be infinite.
Syntax / Usage
Calling a generator returns an iterator without running the body. Each next() advances to the following yield; yield* delegates to another iterable.
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i
}
}
const it = range(0, 5)
console.log(it.next()) // { value: 0, done: false }
console.log([...range(0, 5)]) // [0, 1, 2, 3, 4]
function* combined() {
yield* range(0, 2)
yield* ['a', 'b']
}
console.log([...combined()]) // [0, 1, 'a', 'b']
Examples
Implement a custom iterable by defining Symbol.iterator:
const evens = {
*[Symbol.iterator]() {
let n = 0
while (true) yield (n += 2) // infinite sequence
},
}
const iter = evens[Symbol.iterator]()
console.log(iter.next().value) // 2
console.log(iter.next().value) // 4
Generators can receive values back through next(value):
function* accumulator() {
let total = 0
while (true) {
const amount = yield total // pauses, resumes with the passed value
total += amount
}
}
const acc = accumulator()
acc.next() // prime the generator
console.log(acc.next(10).value) // 10
console.log(acc.next(5).value) // 15
Take only the first N items from an infinite generator:
function take(iterable, count) {
const out = []
for (const value of iterable) {
if (out.length >= count) break
out.push(value)
}
return out
}
function* naturals() {
let n = 1
while (true) yield n++
}
console.log(take(naturals(), 3)) // [1, 2, 3]
Common Mistakes
- Spreading an infinite generator with
[...gen], which never terminates - Forgetting the first
next()call is needed to reach the firstyieldwhen passing values in - Assuming a generator can be restarted—once exhausted, it stays
done - Confusing
yieldwithreturn; areturninside a generator sets the finaldonevalue - Expecting
for...ofto work on a plain object that lacksSymbol.iterator
See Also
functions array-methods javascript-event-loop