DEV Community

DevCorner2
DevCorner2

Posted on

🔄 Mastering JavaScript Generator Functions: A Practical Guide

JavaScript offers several powerful tools for controlling flow, and one of the most flexible—but underutilized—is the Generator Function. Generators allow functions to pause execution and resume later, making them incredibly useful for scenarios like lazy evaluation, streaming data, and asynchronous iteration.


📘 Table of Contents

  1. What Are Generator Functions?
  2. Syntax and Basics
  3. Understanding yield and next()
  4. Real-World Use Cases
  • Use Case 1: Lazy Pagination
  • Use Case 2: Infinite Sequence Generator
  • Use Case 3: Custom Iterable Objects
  • Use Case 4: Controlled Execution for Testing
    1. Best Practices
    2. Generator vs Async/Await
    3. Summary

1. 🧠 What Are Generator Functions?

Generator functions are functions that can be paused and resumed. They return an iterator object that adheres to the Iterator Protocol, which has a .next() method to retrieve the next value.


2. ✍️ Syntax and Basics

function* myGenerator() {
  yield 1;
  yield 2;
  yield 3;
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const gen = myGenerator();

console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
Enter fullscreen mode Exit fullscreen mode

3. 🛠 How yield and next() Work

yield:

  • Pauses the function
  • Returns a value
  • Saves the state of the function

next():

  • Resumes the function from the last yield
  • Returns { value: X, done: false } until the function ends
  • At the end: { value: undefined, done: true }

4. 🔍 Real-World Use Cases

✅ Use Case 1: Lazy Pagination (Batch Processing)

Ideal for handling large datasets in smaller, manageable chunks.

function* paginate(data, size) {
  for (let i = 0; i < data.length; i += size) {
    yield data.slice(i, i + size);
  }
}

const data = Array.from({ length: 100 }, (_, i) => i + 1);
const paged = paginate(data, 10);

console.log(paged.next().value); // [1...10]
console.log(paged.next().value); // [11...20]
Enter fullscreen mode Exit fullscreen mode

♾️ Use Case 2: Infinite Sequence Generator

Useful in simulations, auto-increment IDs, or streaming tokens.

function* idGenerator() {
  let id = 0;
  while (true) {
    yield id++;
  }
}

const ids = idGenerator();
console.log(ids.next().value); // 0
console.log(ids.next().value); // 1
Enter fullscreen mode Exit fullscreen mode

🔁 Use Case 3: Custom Iterable Objects

Generators can make any object iterable using the [Symbol.iterator] protocol.

const myRange = {
  start: 1,
  end: 5,
  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
};

for (let num of myRange) {
  console.log(num); // 1, 2, 3, 4, 5
}
Enter fullscreen mode Exit fullscreen mode

🧪 Use Case 4: Controlled Execution (e.g. for Testing)

Generators allow step-by-step execution, ideal for mocking or testing.

function* testSteps() {
  console.log('Step 1');
  yield;
  console.log('Step 2');
  yield;
  console.log('Step 3');
}

const test = testSteps();
test.next(); // logs: Step 1
test.next(); // logs: Step 2
test.next(); // logs: Step 3
Enter fullscreen mode Exit fullscreen mode

5. 💡 Best Practices

Tip Why
Use for...of to consume generators Cleaner and more readable
Avoid infinite loops unless controlled Can crash the app if not handled properly
Combine with yield* for delegation Great for modular generators
Don't mutate external state Keep generators pure for testability

6. ⚔️ Generator vs Async/Await

Feature Generator Async/Await
Pause/resume ✅ Yes ❌ No
Async operations ❌ Not directly ✅ Yes
Use case Streams, lazy data Async I/O
Syntax yield, next() await, async function

You can even create async generators:

async function* fetchPages(urls) {
  for (let url of urls) {
    const res = await fetch(url);
    yield res.json();
  }
}
Enter fullscreen mode Exit fullscreen mode

✅ Summary

JavaScript Generators are powerful, lightweight, and elegant tools to handle:

  • Custom iteration
  • Infinite sequences
  • On-demand data processing
  • Simulation/test frameworks

Use them when you need controlled, lazy, or infinite data flow—and you’ll write cleaner and more efficient code.

Top comments (0)