Generators
A generator function is a special type of function in JavaScript that can pause its execution and then continue it from the same place.
This is a very powerful tool - it lets you write iterators, lazy computations, asynchronous loops and much more. Let's break it down step by step.
1. Definition
A generator function is a function that returns a generator object (an iterator), and inside itself uses the
yieldkeyword to pause execution and return values one at a time.
2. Syntax
function* name([args]) {
// function body
}- the
*afterfunctionmakes the function a generator; yieldis used to produce values "step by step";- when called, it does not run immediately, it returns a generator (an iterator).
3. Example - a basic generator
function* gen() {
yield 1;
yield 2;
yield 3;
}
const iterator = gen();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }What happens:
- on the first call to
next(), execution reaches the firstyield, returns 1 and "freezes"; - on the next
next(), execution continues from the same place; - after the last
yield, the generator finishes (done: true).
4. Generators are iterators
A generator returns an object compatible with the iterator protocol.
So it can be used in for...of:
function* numbers() {
yield 10;
yield 20;
yield 30;
}
for (const n of numbers()) {
console.log(n);
}Output:
10
20
305. Example - an infinite generator
Generators can be infinite - they don't build the whole array at once, they yield values "on demand".
function* infiniteCounter() {
let i = 1;
while (true) {
yield i++;
}
}
const counter = infiniteCounter();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
console.log(counter.next().value); // 3
// ...and so on infinitelyThis is an example of lazy computation - values are generated as needed.
6. Passing values into a generator
You can pass data back into a generator via next(value).
function* dialog() {
const name = yield 'What is your name?';
yield `Hello, ${name}!`;
}
const it = dialog();
console.log(it.next().value); // "What is your name?"
console.log(it.next('Tim').value); // "Hello, Tim!"The first next() starts the generator,
the second passes 'Tim' in as the result of the yield expression.
7. Using return
You can end a generator early using return:
function* example() {
yield 1;
return 'end';
yield 2; // will not run
}
const it = example();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 'end', done: true }8. Asynchronous generators (ES2018)
Asynchronous generators let you work with await inside iterable data streams.
async function* fetchData() {
yield await Promise.resolve('First part');
yield await Promise.resolve('Second part');
}
for await (const part of fetchData()) {
console.log(part);
}Asynchronous generators use for await...of for asynchronous iteration.
9. Why generators are needed
| Use case | Example |
|---|---|
| Building iterators | Element-by-element data generation |
| Lazy computation | No need to store the whole array |
| Step-by-step execution | Controlling the execution flow |
| Asynchronous pipelines | Processing data streams without loading everything into memory |
| Coroutine emulation | The ability to "stop" and "resume" code |
10. Example - a range generator
function* range(start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
for (const num of range(1, 5)) {
console.log(num);
}Output:
1
2
3
4
5SUMMARY
| Property | Description |
|---|---|
| Definition | A function declared with function* that returns an iterator |
| Returns | A generator object |
| Keyword | yield |
| Can pause execution | Yes |
| Can pass values back | Yes |
| Asynchronous version | async function* |
| Main use | Lazy computation, iterators, asynchronous streams |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.