Skip to content

Intermediate · Map, Set, iterators, generators and regular expressions · topic 33 of 61 · 25 min

Generators

Explanation

A generator function, written function*, can pause with yield and resume later. Calling it returns a generator object, which is both an iterator and an iterable. Generators make lazy and even infinite sequences easy to write, such as ID generators or paging through data.

Why generators?

Writing an iterator by hand, as in the last topic, needs an object, a next method and manual state. A generator function writes the same thing as normal-looking code. Each yield hands out one value and pauses the function right there, keeping all its local variables, until the next value is requested.

javascript
function* trafficLight() {
  yield 'green';
  yield 'yellow';
  yield 'red';
}
const light = trafficLight();   // nothing runs yet!
console.log(light.next());      // { value: 'green', done: false }
console.log(light.next().value);// 'yellow'
console.log([...trafficLight()]); // ['green', 'yellow', 'red']

Calling trafficLight() does not run its body. It returns a generator object. The body runs only when next() is called, and only until the next yield.

Lazy and infinite sequences

Because a generator only works when asked, it can describe an endless sequence. The consumer decides when to stop.

javascript
function* orderIds(prefix) {
  let n = 1;
  while (true) yield `${prefix}-${String(n++).padStart(5, '0')}`;
}
function* take(iterable, count) {
  if (count <= 0) return;
  for (const x of iterable) {
    yield x;
    if (--count === 0) return;
  }
}
console.log([...take(orderIds('OD'), 3)]); // ['OD-00001', 'OD-00002', 'OD-00003']
Careful: Never spread or for…of an infinite generator without a stop: [...orderIds('OD')] runs forever and freezes the program. Always limit it with take, a break, or a condition.

return and yield*

return inside a generator ends it (done becomes true). yield* other hands out every value of another iterable, which lets generators delegate to each other.

javascript
function* menu() {
  yield* ['idli', 'dosa'];
  yield* ['vada'];
  return 'end';                 // value of the final { done: true } result
}
console.log([...menu()]);       // ['idli', 'dosa', 'vada'] (the return value is not included)

Generators as data pipelines

javascript
function* filterGen(iter, test) { for (const x of iter) if (test(x)) yield x; }
function* mapGen(iter, fn) { for (const x of iter) yield fn(x); }
const rows = ['12,Asha', 'bad', '7,Ravi'];
const parsed = mapGen(filterGen(rows, (r) => r.includes(',')), (r) => r.split(',')[1]);
console.log([...parsed]); // ['Asha', 'Ravi'] (one row at a time, never all at once)

Each step pulls one item through the whole pipeline before the next item is read. For a 5 GB log file read line by line, memory stays small.

Async generators (a preview)

async function* combines generators with promises, and for await…of consumes them. They are ideal for reading a stream of network pages or file chunks. You will learn promises in module 8.

Think of it like this: A generator is like a chef cooking dosas to order in a small stall. He does not cook 500 dosas in the morning; each time a customer asks (next), he makes one, hands it over (yield), and waits. He remembers where he left off, batter and all.
Tip: Generators are not needed every day, but they appear in libraries (Redux-Saga used them heavily), in interview questions, and whenever you process big or endless data lazily.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Generators · 1/6

Generators

In this lesson you will write generators, functions that can pause and resume.

Prefer a video by a teacher? Find free videos on “javascript generators yield function* explained” on YouTube ↗

In real life: Generating invoice numbers for the financial year

An accounting tool numbers invoices like INV/2026-27/0001. A generator produces the next number on demand, and the billing code just calls next() each time a bill is saved.

javascript
function* invoiceNumbers(fy) {
  let n = 1;
  while (true) yield `INV/${fy}/${String(n++).padStart(4, '0')}`;
}
const numbers = invoiceNumbers('2026-27');
console.log(numbers.next().value); // INV/2026-27/0001
console.log(numbers.next().value); // INV/2026-27/0002

Practice (0/3 done)

Task 1 · Code · Javascript

Write a generator function countdown(n) that yields n, n - 1, … down to 1.

Task 2 · Code · Javascript

Write take(iterable, count) as a generator that yields at most count values from any iterable, even an infinite one. Also write naturals() as an infinite generator 1, 2, 3, …

Task 3 · Code · Javascript

Write a generator fibonacci() that yields 0, 1, 1, 2, 3, 5, … forever. Test code will take only the first few values.

Quick quiz

Question 1

1.What does calling a generator function return?

Question 2

2.function* g() { yield 1; return 2; } What is [...g()]?

Question 3

3.What does yield* [1, 2] do inside a generator?

Question 4

4.Why can a generator describe an infinite sequence safely?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does calling a generator function return?

Answer: A generator object

The body does not run until next() is called.

function* g() { yield 1; return 2; } What is [...g()]?

Answer: [1]

Spread stops at done: true and ignores the return value.

What does yield* [1, 2] do inside a generator?

Answer: Yields 1 then 2

yield* delegates to another iterable, yielding each of its values.

Why can a generator describe an infinite sequence safely?

Answer: It produces values only when asked

Generators are lazy and pause at each yield.

What happens when you call a function that contains yield?Related

Answer: It returns a generator object; the body runs only when values are asked for

Calling a generator function only creates the generator. Each next() runs the body up to the next yield.

From Iterators and generators

What does an iterator's next() return?Related

Answer: An object { value, done }

next() returns { value, done }.

From Iterators and the iteration protocol

async function f() { return 3; } What is f()?Related

Answer: A promise that fulfils with 3

async functions always return promises.

From async and await

How many items are in {c for c in "banana"}?Related

Answer: 3

A set keeps each value once: b, a and n.

From List, dict and set comprehensions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Map, Set, iterators, generators and regular expressions” before its exam: Regular expressions: the basics, Regular expressions in practice.
  2. Module 7 exam: Collections, iterators and regular expressions · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Asynchronous JavaScript. 61 topics left in the course before the final exam.

← Previous: Iterators and the iteration protocol