, ,

You Didn’t Know Generators Could Handle Infinite Loops This Easily

Posted by

JavaScript generators aren’t just about iteration; they can tame infinite loops and streams of data without blowing up your memory or CPU.


Introduction

Every developer has faced this dilemma:

  • You want to generate an endless sequence (like IDs, timestamps, or random numbers).
  • But a naive infinite loop either crashes your app or locks up the browser.
  • You try to hack it with counters, arrays, or async intervals, and it gets messy.

👉 Enter JavaScript generators.

Generators let you pause and resume functions, which means you can write infinite loops that behave gracefully: no crashes, no runaway memory, and no wasted CPU cycles.

In this post, we’ll cover:

  • ✅ What generators are and how they work
  • ✅ How to write infinite loops with generators safely
  • ✅ Real-world use cases (IDs, streams, pagination, async pipelines)
  • ✅ Common mistakes and gotchas
  • ✅ Pro tips for mixing generators with async/await

What Are Generators in JavaScript?

A generator function looks like a normal function, but uses an asterisk (function*) and the yield keyword.

Example:

function* numbers() {
yield 1;
yield 2;
yield 3;
}

const gen = numbers();
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 }
  • Each yield pauses the function.
  • .next() Resumes it.
  • You don’t get everything at once; you pull values on demand.

The Infinite Loop Problem

Normally, an infinite loop like this would lock your app:

while (true) {
console.log("Hello, world");
}

This never stops. Your browser freezes. Your app dies.


The Generator Solution

With a generator, you can write an infinite loop that only produces values when asked:

function* infiniteCounter() {
let i = 0;
while (true) {
yield i++;
}
}

const counter = infiniteCounter();
console.log(counter.next().value); // 0
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
// ... and so on

✅ No crash. ✅ Infinite potential values. ✅ Controlled execution.


Real-World Use Cases

1. Unique IDs Without Global State

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

const getId = idGenerator();

console.log(getId.next().value); // 1
console.log(getId.next().value); // 2
console.log(getId.next().value); // 3

Instead of let currentId = 0;You get a clean, self-contained generator.


2. Paginating API Results

function* paginate(api, pageSize = 10) {
let page = 1;
while (true) {
const results = api(page, pageSize);
if (!results.length) return; // stop
yield results;
page++;
}
}

// Usage
for (const page of paginate(fetchUsers, 10)) {
console.log(page);
}

You can fetch “infinite” pages without knowing how many exist.


3. Streaming Data

Generators pair perfectly with async iteration for streams:

async function* messageStream(socket) {
for await (const msg of socket) {
yield msg;
}
}

(async () => {
for await (const message of messageStream(mySocket)) {
console.log("New message:", message);
}
})();

This is infinite message handling without blowing up memory.


4. Random Number Generators

function* randomNumbers() {
while (true) {
yield Math.random();
}
}

const rng = randomNumbers();
console.log(rng.next().value); // random value
console.log(rng.next().value); // another random value

Great for simulations, testing, or procedural generation.


Gotchas with Generators

  • Not automatic: A generator won’t run by itself. You need .next() or for..of.
  • No memory leaks by default, but if you have yield huge objects, you can still bloat memory.
  • Be careful with async: Use async function* for streams, otherwise you’ll get sync values only.
  • They don’t replace all loops: Sometimes a plain loop is simpler.

Pro Tips

  1. Combine with Iterators
     Generators are iterators that you can plug directly into for..of, map, reduce, etc.
  2. Lazy Evaluation = Performance Win
     Instead of computing everything up front, you only compute what you need when you need it.
  3. Stop with return
     You can break infinite generators gracefully with a return.
  4. Mix with Async/Await
     async function* Let’s you create async streams (perfect for APIs, sockets, or files).

Conclusion

Infinite loops in JavaScript don’t have to mean frozen browsers or stack overflows. With generators, you can:

  • Build infinite sequences safely
  • Handle streams and pagination elegantly
  • Write code that’s lazy, efficient, and memory-friendly

Key takeaway: Generators make infinite loops not only possible but practical in modern JavaScript.


Call to Action

Have you ever used generators beyond the basic “yield” demo?
Drop your experience in the comments 👇

And if you know a teammate who still avoids generators because they “look weird,” share this post. It might change how they code forever.

Leave a Reply

Your email address will not be published. Required fields are marked *