JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsjavascriptGenerators & Iterators
PrevNext
javascript
advanced
12 min read

Generators & Iterators

async-generators
es6
generators
iterators
lazy-evaluation
symbol-iterator
yield

Generators are functions that can pause and resume execution using yield, producing values on demand. They implement the iterator protocol, enabling lazy evaluation, infinite sequences, and custom iteration with for...of.

Key Points

1Generator Functions

Declared with function* syntax, yield pauses execution and produces a value. Calling the function returns a Generator object, not the result.

2Iterator Protocol

next() returns { value, done }. Generators implement both the iterator and iterable protocols, working with for...of and spread syntax.

3Lazy Evaluation

Values are computed only when requested via next() — memory-efficient for large datasets since only one value exists at a time.

4Two-Way Communication

generator.next(value) sends data into the generator; yield receives it. generator.throw(error) injects errors that the generator can catch.

5Async Generators

async function* with for await...of enables lazy asynchronous iteration — useful for streaming data, paginated APIs, and chunked file processing.

What You'll Learn

  • Explain how generators work and the difference between yield and return
  • Implement custom iterables using Symbol.iterator and generator functions
  • Know when to use generators vs arrays for data processing

Deep Dive

Generators are special functions that can pause their execution at any point and resume later, producing a sequence of values on demand rather than computing them all at once. They implement the iterator protocol, making them work seamlessly with for...of loops and spread syntax.

Generator Functions

Declared with function* syntax (the asterisk can be placed anywhere between function and the name). Inside a generator, the yield keyword pauses execution and produces a value. The function's state (local variables, execution position) is preserved between pauses.

Calling a generator function does not execute its body — it returns a Generator object that conforms to the iterator protocol. The body only executes when you call .next() on the generator.

The Iterator Protocol

An iterator is any object with a next() method that returns { value, done }. value is the yielded value, and done is true when the generator has finished (returned). Generators automatically implement this protocol.

The iterable protocol requires a [Symbol.iterator]() method that returns an iterator. Arrays, strings, Maps, and Sets are built-in iterables. Generator objects are both iterators and iterables — they have next() and [Symbol.iterator]() returns themselves.

Lazy Evaluation

Generators compute values only when requested. If you have a generator that yields a million items but you only call next() three times, only three values are computed. This makes generators memory-efficient for large datasets — unlike arrays that must hold all values in memory at once.

Infinite Sequences

Because values are generated on demand, generators can represent infinite sequences:

JavaScript
function* naturals() {
  let n = 1;
  while (true) yield n++;
}

This never runs out of memory because it only produces one number at a time. Use it with for...of and break, or with manual next() calls.

Two-Way Communication

The yield keyword can also receive values. Calling generator.next(value) passes value back into the generator as the result of the yield expression. This enables two-way communication: the generator yields data out, and the consumer sends data in. The first next() call cannot send a value (there's no yield waiting to receive it).

generator.return(value) forces the generator to finish as if it hit a return statement. generator.throw(error) throws an error inside the generator at the point of the last yield, which the generator can catch with try/catch.

Custom Iterables

You can make any object work with for...of by implementing [Symbol.iterator] as a generator:

JavaScript
const range = {
  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) yield i;
  },
  start: 1, end: 5
};
for (const n of range) console.log(n); // 1, 2, 3, 4, 5

Async Generators

async function* combines generators with async/await. They yield promises and are consumed with for await...of. Use cases include streaming data, paginated API calls, and processing large files chunk by chunk.

Key Interview Distinction

Generators enable lazy, on-demand value production — they pause at yield and resume at next(). They implement the iterator protocol automatically. The two main use cases are: lazy evaluation of large/infinite sequences, and making custom objects iterable. Async generators extend this to asynchronous data streams.

Fun Fact

Before async/await existed, generators were used to write asynchronous code that looked synchronous — libraries like co (by TJ Holowaychuk) would automatically advance the generator when promises resolved. This pattern directly inspired the async/await syntax that was standardized in ES2017.

Learn These First

Functions

beginner

Promises & Async/Await

intermediate

Continue Learning

Promises & Async/Await

intermediate

Closures

intermediate

Practice What You Learned

What are Generators in JavaScript and when would you use them?
senior
generators
Generators are functions that can pause execution and resume later, yielding multiple values over time. They're defined with function* syntax and return an iterator. Use cases include lazy evaluation, infinite sequences, and custom iterables.
Previous
Functions
Next
Hoisting
PrevNext