# JavaScript Generators (function*) Explained with Examples

Source: https://devdocs10.com/articles/javascript/js-generators  
By Murat Bo · Updated 2026-10-17 · DevDocs10 (https://devdocs10.com)

JavaScript generators let you pause a function and continue it later, which makes them useful for custom iteration, lazy values, and step-by-step control flow. They are a core part of the iteration model in modern JavaScript.

> **Quick answer:** A generator is a function declared with `function*` that can pause with `yield` and resume later with `next()`. It returns a generator object that follows the iterator protocol.

> **Difficulty:** Intermediate
>
> **You'll understand this better if you know:** how functions work in JavaScript, what arrays and loops do, and the basics of objects and return values.

## 1. What Are JavaScript Generators?

A generator is a special kind of function that does not run from top to bottom in one pass. Instead, it can stop at a `yield` statement and continue later from the same point.

- Generators are declared with `function*`.
- They return a generator object, not a final value immediately.
- They work with the iterator protocol, so they can be used in loops and custom iteration patterns.
- They are useful when you want values one at a time instead of all at once.

Think of a generator as a paused function with memory of where it stopped and what local variables it already has.

## 2. Why JavaScript Generators Matter

Generators matter because they give you fine-grained control over iteration and computation. Instead of building a full array first, you can produce values only when they are needed.

This helps with:

- lazy evaluation, where values are computed on demand
- custom iterables that behave like built-in collections
- multi-step processes that need to pause and resume
- cleaner code for some stateful workflows, such as parsers or task runners

They are not required for everyday looping, but they are very valuable when you need custom iteration behavior or want to avoid doing all work up front.

## 3. Basic Syntax

A generator is written with `function*`, and it uses `yield` to produce values one at a time.

### Minimal generator syntax

The following example shows the simplest possible generator.

```javascript
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
}

const numbers = countToThree();

console.log(numbers.next()); // { value: 1, done: false }
console.log(numbers.next()); // { value: 2, done: false }
console.log(numbers.next()); // { value: 3, done: false }
console.log(numbers.next()); // { value: undefined, done: true }
```

Output (tested with Node 24.21.0):

```text
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }
```

Each call to `next()` resumes the function until the next `yield` or until the function finishes.

### How `yield` works

The `yield` keyword both produces a value and pauses execution. When the generator resumes, it continues from the next line after that `yield`.

```javascript
function* demo() {
  console.log("before");
  yield "paused";
  console.log("after");
}

const iter = demo();
iter.next(); // logs "before"
iter.next(); // logs "after"
```

Output (tested with Node 24.21.0):

```text
before
after
```

This shows that a generator preserves local state between calls.

## 4. Step-by-Step Examples

### Example 1: Iterating through names

Here is a generator that yields a few strings in sequence. This is a simple way to see the iteration pattern.

```javascript
function* names() {
  yield "Ada";
  yield "Grace";
  yield "Linus";
}

for (const name of names()) {
  console.log(name);
}
```

Output (tested with Node 24.21.0):

```text
Ada
Grace
Linus
```

The generator can be used directly in `for...of` because it is iterable.

### Example 2: Passing values back into a generator

A generator can receive values through `next(value)`. The first call starts the function, and later calls can send data back in.

```javascript
function* askName() {
  const name = yield "What is your name?";
  return `Hello, ${name}!`;
}

const greeting = askName();
console.log(greeting.next().value); // "What is your name?"
console.log(greeting.next("Ava").value); // "Hello, Ava!"
```

Output (tested with Node 24.21.0):

```text
What is your name?
Hello, Ava!
```

This example shows that generators can pause, ask for input, and then continue.

### Example 3: Infinite sequence with lazy output

Generators are especially useful for sequences that do not need to be fully stored in memory.

```javascript
function* naturalNumbers() {
  let n = 1;

  while (true) {
    yield n;
    n = n + 1;
  }
}

const nums = naturalNumbers();
console.log(nums.next().value); // 1
console.log(nums.next().value); // 2
console.log(nums.next().value); // 3
```

Output (tested with Node 24.21.0):

```text
1
2
3
```

Because values are produced only when requested, this pattern avoids allocating a huge array up front.

### Example 4: Delegating to another generator with `yield*`

The `yield*` syntax forwards iteration to another iterable or generator.

```javascript
function* partOne() {
  yield "A";
  yield "B";
}

function* partTwo() {
  yield "C";
}

function* allLetters() {
  yield* partOne();
  yield* partTwo();
}

console.log([...allLetters()]); // ["A", "B", "C"]
```

Output (tested with Node 24.21.0):

```text
[ "A", "B", "C" ]
```

This is useful when one generator is built from smaller pieces.

## 5. Practical Use Cases

- Building custom iterables, such as a tree traversal or a range helper.
- Producing large sequences lazily instead of creating big arrays.
- Implementing stateful workflows, such as tokenizers or simple parsers.
- Breaking a task into staged steps where each step can pause and resume.
- Forwarding data from one iterable into another with `yield*`.

Generators are usually a design choice for controlled iteration, not a replacement for every array method or loop.

## 6. Common Mistakes

### Mistake 1: Forgetting to call the generator

A generator function returns a generator object only after you call it. If you try to iterate over the function itself, the code will not behave as expected.

**Problem:** The function reference is not iterable, so the loop fails or produces the wrong result.

```javascript
function* letters() {
  yield "x";
  yield "y";
}

for (const letter of letters) {
  console.log(letter);
}
```

Output (tested with Node 24.21.0):

```text
Uncaught TypeError: letters is not iterable
```

**Fix:** Call the generator function so you get the iterable generator object.

```javascript
function* letters() {
  yield "x";
  yield "y";
}

for (const letter of letters()) {
  console.log(letter);
}
```

Output (tested with Node 24.21.0):

```text
x
y
```

The corrected version works because `letters()` returns an iterable generator object.

### Mistake 2: Using `return` when you meant `yield`

`return` ends the generator immediately. If you want multiple values, use `yield` for each value you want to produce.

**Problem:** The generator stops after the first `return`, so later values are never produced.

```javascript
function* colors() {
  return "red";
  yield "green";
  yield "blue";
}
```

**Fix:** Use `yield` for values that should be produced during iteration, and reserve `return` for the final completion value if needed.

```javascript
function* colors() {
  yield "red";
  yield "green";
  yield "blue";
}
```

The fixed version produces each color in sequence as intended.

### Mistake 3: Expecting `next()` to return the yielded value directly

The `next()` method returns an object with both `value` and `done`. New developers often log the whole object or try to use it as if it were the raw value.

**Problem:** This code treats the result object like a plain string, which leads to confusing output or logic bugs.

```javascript
function* numbers() {
  yield 10;
}

const value = numbers().next();
console.log(value + 1);
```

Output (tested with Node 24.21.0):

```text
[object Object]1
```

**Fix:** Read the `value` property from the iterator result.

```javascript
function* numbers() {
  yield 10;
}

const result = numbers().next();
console.log(result.value + 1);
```

Output (tested with Node 24.21.0):

```text
11
```

The corrected version works because you are using the actual yielded value, not the wrapper object.

## 7. Best Practices

### Use generators when values are naturally produced one at a time

Generators are a good fit for sequences, traversals, and on-demand computation. They are less helpful when you already have all data available and just need a simple array.

```javascript
function* range(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}
```

This keeps the code readable and avoids unnecessary arrays when you only need a stream of values.

### Keep generator state small and meaningful

A generator stores its local variables between pauses, so it is best to keep only the state you actually need.

```javascript
function* pager(pages) {
  let index = 0;

  while (index < pages.length) {
    yield pages[index++];
  }
}
```

That makes the generator easier to understand and reduces accidental complexity.

### Prefer `for...of` when you only need iteration

If you do not need to control each `next()` call manually, use `for...of` for simpler code.

```javascript
function* ids() {
  yield 101;
  yield 102;
}

for (const id of ids()) {
  console.log(id);
}
```

Output (tested with Node 24.21.0):

```text
101
102
```

This is usually clearer than manually calling `next()` several times.

## 8. Limitations and Edge Cases

- A generator is not restartable. Once it finishes, you must call the generator function again to get a new iterator.
- `yield` can only be used inside a generator function, not in a normal function.
- Generators are synchronous. They do not automatically wait for promises or perform asynchronous iteration.
- If you break out of a `for...of` loop early, the generator is closed and cannot continue from that point.
- The first `next()` call cannot send a useful value into the generator because execution has not reached the first `yield` yet.

> **Tip:** If you need asynchronous iteration, look at async generators and `for await...of` instead of regular generators.

## 9. Practical Mini Project

Let’s build a small range utility that uses a generator to produce numbers lazily and then consumes them in different ways.

```javascript
function* range(start, end, step = 1) {
  if (step <= 0) {
    throw new Error("step must be greater than 0");
  }

  for (let n = start; n <= end; n += step) {
    yield n;
  }
}

const values = [...range(2, 10, 2)];
console.log(values); // [2, 4, 6, 8, 10]

for (const value of range(1, 5)) {
  console.log(value);
}
```

Output (tested with Node 24.21.0):

```text
[ 2, 4, 6, 8, 10 ]
1
2
3
4
5
```

This mini project shows how a generator can behave like a reusable sequence builder. The same `range` logic can be consumed as an array or directly in a loop.

## 10. Key Points

- Generators are functions declared with `function*` that can pause with `yield`.
- They return generator objects that support the iterator protocol.
- `next()` advances execution and returns an object with `value` and `done`.
- `yield*` delegates iteration to another iterable or generator.
- Generators are best for lazy values, custom iteration, and stateful workflows.

## 11. Practice Exercise

Build a generator that produces the first five odd numbers starting from 1.

- Create a generator function named `oddNumbers`.
- Use `yield` to produce five values.
- Consume the generator with `for...of` and print each number.

**Expected output:**

```javascript
1
3
5
7
9
```

**Hint:** Start at 1 and add 2 after each yield.

**Solution:**

```javascript
function* oddNumbers() {
  let current = 1;

  for (let count = 0; count < 5; count++) {
    yield current;
    current += 2;
  }
}

for (const value of oddNumbers()) {
  console.log(value);
}
```

Output (tested with Node 24.21.0):

```text
1
3
5
7
9
```

## 12. Final Summary

JavaScript generators give you a way to pause and resume a function, making them ideal for custom iteration and lazy value production. The combination of `function*`, `yield`, `next()`, and `yield*` forms a flexible toolset for advanced iteration patterns.

For beginners, the most important idea is that a generator is not a regular function call. It creates an iterator that you drive step by step. Once that mental model clicks, generators become much easier to use for ranges, traversals, and stateful workflows.

If you want to continue learning, the next natural topic is the iterator protocol and how generators relate to `for...of`, arrays, and async generators.

## Browser Support

| Feature | Status | Chrome | Edge | Firefox | Safari | Safari iOS |
| --- | --- | --- | --- | --- | --- | --- |
| Generators | Widely available since Mar 2019 | 39+ | 13+ | 26+ | 10+ | 10+ |
| Async generators | Widely available since Jul 2022 | 63+ | 79+ | 57+ | 12+ | 12+ |

Data: web-features 3.43.0 (MDN Baseline).
