# How JavaScript Generators and Yield Work: A Complete Guide to `function*` and Iteration Control

> Understand how JavaScript generators and yield work with function* and iteration control. Master pausing and resuming function execution for efficient code.

- Repository: [Lydia Hallie/javascript-questions](https://github.com/lydiahallie/javascript-questions)
- Tags: deep-dive
- Published: 2026-03-04

---

**JavaScript generators are special functions declared with `function*` that use the `yield` keyword to pause execution and resume later, returning a generator object that conforms to the iterator protocol.**

The `lydiahallie/javascript-questions` repository provides comprehensive documentation on how JavaScript generators and yield enable memory-efficient iteration and asynchronous data streams. This guide examines the source code at specific line ranges in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) to explain the mechanics of generator objects, state suspension, and delegation patterns.

## What Are JavaScript Generators?

Unlike regular functions that run to completion upon invocation, **generator functions** use the `function*` syntax to return a generator object immediately without executing the function body. As documented in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) around line 1345, this generator object implements the iterator protocol, exposing `next()`, `return()`, and `throw()` methods.

When you invoke a generator function, JavaScript creates an internal state machine that tracks local variables, the current `this` context, and the execution pointer. This state remains frozen between calls, allowing the function to resume exactly where it left off.

## How the `yield` Keyword Controls Execution

The `yield` keyword is the mechanism that pauses generator execution. Each time the generator encounters a `yield` expression, it produces the supplied value and suspends its internal state. According to the source analysis of `lydiahallie/javascript-questions`, this suspension includes preserving local variable bindings and the execution context.

When you call `gen.next()` on the generator object, execution resumes from the exact point of the last `yield`. The `next()` method returns an object with two properties:

- `value`: The value yielded by the generator
- `done`: A boolean indicating whether the generator has completed

Once the generator function exhausts all `yield` statements and reaches the end of the function body, subsequent calls to `next()` return `{ value: undefined, done: true }`.

## Delegating Iteration with `yield*`

The `yield*` expression delegates iteration to another generator or iterable object. As shown in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) around line 3643, `yield*` forwards control to the inner iterator, yielding each of its values in turn before resuming the outer generator.

This delegation pattern allows you to compose generators cleanly, reusing existing iteration logic without manually looping through the inner iterable. The outer generator pauses until the delegated iterator completes, then continues execution with the next statement after the `yield*` expression.

## Async Generators and `for await...of`

JavaScript extends generator concepts to asynchronous contexts with `async function*` syntax. As documented near line 4036 in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md), async generators yield Promises instead of immediate values, enabling consumption via `for await...of` loops or manual `await gen.next()` calls.

This pattern is particularly effective for streaming data sources where values arrive over time, such as reading files line-by-line or processing network chunks. The async generator handles backpressure naturally, pausing execution until the consumer requests the next value.

## Practical Code Examples from the Source

The `lydiahallie/javascript-questions` repository provides concrete implementations demonstrating these concepts. Below are the canonical examples referenced in the source analysis.

### Basic Generator with `yield`

This example from [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) (lines 1345-1360) demonstrates the fundamental pause-and-resume behavior:

```javascript
// Basic generator – yields numbers 0, 1, 2
function* countToTwo() {
  yield 0;
  yield 1;
  yield 2;
}
const gen = countToTwo();
console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: undefined, done: true }

```

### Delegating with `yield*`

The delegation pattern shown around line 3643 illustrates composition:

```javascript
// Delegating with yield*
function* letters() {
  yield* ['a', 'b', 'c']; // forwards to the array iterator
}
function* combined() {
  yield* countToTwo();    // re‑use the previous generator
  yield* letters();       // then yield letters
}
for (const v of combined()) {
  console.log(v);
}
// Output: 0 1 2 a b c

```

### Async Generator for Streaming Data

The async implementation near line 4036 demonstrates Promise-based iteration:

```javascript
// Async generator – streams numbers with a delay
async function* slowRange(start, end) {
  for (let i = start; i <= end; i++) {
    await new Promise(r => setTimeout(r, 500)); // 0.5 s pause
    yield i;
  }
}
(async () => {
  for await (const n of slowRange(1, 3)) {
    console.log(n); // logs 1, then 2, then 3 every 0.5 s
  }
})();

```

### Infinite Sequences with Memory Efficiency

This pattern demonstrates lazy evaluation for unbounded sequences:

```javascript
// Using a generator to implement a simple iterator protocol
function* fibonacci() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2

```

## Summary

- **JavaScript generators** use `function*` syntax to create objects that implement the iterator protocol, allowing functions to pause and resume execution while maintaining internal state.
- The **`yield`** keyword suspends the generator, preserving local variables and execution context, while `gen.next()` resumes operation returning `{ value, done }`.
- **`yield*`** delegates iteration to another generator or iterable, enabling composition of complex iteration logic without manual looping.
- **Async generators** (`async function*`) extend these patterns to Promise-based streams, consumable via `for await...of` loops for handling asynchronous data sources.
- The `lydiahallie/javascript-questions` repository documents these patterns in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) at lines 1345, 3643, and 4036, with translations available in `zh-CN/`, `es-ES/`, and `fr-FR/` directories.

## Frequently Asked Questions

### What is the difference between `yield` and `return` in a JavaScript generator?

While both `yield` and `return` produce values, **`yield` pauses the generator** and preserves its internal state, allowing subsequent `next()` calls to resume execution from the exact suspension point. **`return` terminates the generator permanently**, setting the `done` property to `true` and preventing further iteration. Once a generator returns, subsequent calls to `next()` will continue to return `{ value: undefined, done: true }`.

### Can I use `yield` outside of a generator function?

No, the **`yield` keyword is syntactically valid only inside generator functions** declared with `function*` or `async function*`. Using `yield` in a regular function, arrow function, or method will throw a `SyntaxError`. This restriction exists because `yield` requires the JavaScript engine to create the special execution context and state management infrastructure that generators provide.

### How does `yield*` differ from calling a generator function directly?

**`yield*` delegates iteration** to another generator or iterable, yielding each value from the inner source as if it came directly from the outer generator. Simply calling a generator function (`innerGen()`) returns a generator object without consuming it—you would need to manually iterate and yield each value. `yield*` handles this automatically, preserving the `return` value of the delegated generator as the result of the `yield*` expression itself.

### When should I use an async generator instead of a regular generator?

Use **async generators (`async function*`)** when your iteration logic involves asynchronous operations such as fetching data from APIs, reading streams, or database queries that return Promises. Regular generators cannot handle Promises directly—they execute synchronously. Async generators allow you to `await` asynchronous operations before yielding values, and they are consumed with `for await...of` loops or manual `await gen.next()` calls, making them ideal for streaming asynchronous data sources without loading entire datasets into memory.