Sitemap
Frontend Highlights

Frontend Highlights

This page is about simple frontend things which can be useful in real work Support us on buymeacoffee.com/guestdm or https://ko-fi.com/dm110416

Understanding JavaScript Generators with Practical Examples

4 min readOct 30, 2024

--

JavaScript generators are powerful functions that allow us to pause and resume function execution, offering an alternative to traditional iteration and asynchronous patterns. Generators are particularly useful for handling sequences, streams of data, and complex control flows in JavaScript applications. This article will cover the basics of generators, provide practical examples, and show how you can use them in a React component.

What is a Generator?

A generator in JavaScript is a function that can pause its execution and resume later. Generators are defined using the function* syntax and return a special type of iterator called a generator object, which uses the yield keyword to pause and resume execution.

function* generatorFunction() {
// code here
}

Generators differ from regular functions in two key ways:

  1. They can be paused with yield.
  2. They return values incrementally using next() instead of returning all at once.

Basic Example of a Generator

Let’s start with a simple generator that yields a sequence of numbers.

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

const generator = numberGenerator();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3
console.log(generator.next().done); // true (no more values)

In this example:

  • Each call to next() returns the next value in the sequence.
  • After all yield statements are exhausted, done is set to true.

Practical Example: Generating a Fibonacci Sequence

The Fibonacci sequence is a perfect use case for generators, as it can produce an infinite series of numbers.

function* fibonacciGenerator() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}

const fibGen = fibonacciGenerator();
console.log(fibGen.next().value); // 0
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 2
console.log(fibGen.next().value); // 3
console.log(fibGen.next().value); // 5

Using Generators for Asynchronous Data Flow

Generators are also helpful for managing asynchronous code because they can yield Promises, enabling more flexible control over async workflows.

Example: Fetching Data in Sequence

Let’s fetch data from two APIs sequentially using a generator:

function* fetchData() {
const userResponse = yield fetch('https://jsonplaceholder.typicode.com/users/1');
const postResponse = yield fetch('https://jsonplaceholder.typicode.com/posts/1');
return { user: yield userResponse.json(), post: yield postResponse.json() };
}

async function runGenerator(genFunc) {
const generator = genFunc();
let result = generator.next();

while (!result.done) {
result = generator.next(await result.value);
}
return result.value;
}

runGenerator(fetchData).then(console.log);

Get Frontend Highlights’s stories in your inbox

Join Medium for free to get updates from this writer.

In this example:

  • fetchData fetches a user and then a post.
  • runGenerator controls the generator, awaiting each asynchronous request sequentially.

Using Generators in a React Component

Now, let’s look at how to integrate a generator with a React component. Generators can be helpful for managing complex logic, such as generating sequential IDs, cycling through values, or even implementing paginated data fetching.

Example: Unique ID Generator in a React Component

Suppose we want to generate a unique ID for each item added to a list.

import React, { useState } from 'react';

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

const ItemList = () => {
const [items, setItems] = useState([]);
const generator = idGenerator();

const addItem = () => {
const id = generator.next().value;
setItems([...items, { id, name: `Item ${id}` }]);
};

return (
<div>
<button onClick={addItem}>Add Item</button>
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};

export default ItemList;

In this component:

  • idGenerator yields a new ID each time next() is called.
  • Each click of the button generates a new unique ID, which is added to the items array.

Example: Pagination with Generators

Generators are also useful for lazy-loading data. Let’s create a pagination component where the generator yields a set of items each time a button is clicked.

import React, { useState } from 'react';

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

const data = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`);

const PaginatedList = () => {
const [items, setItems] = useState([]);
const [page, setPage] = useState(0);
const generator = paginatedData(data, 10);

const loadMore = () => {
const nextPage = generator.next().value;
if (nextPage) {
setItems(prevItems => [...prevItems, ...nextPage]);
setPage(page + 1);
}
};

return (
<div>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onClick={loadMore} disabled={page * 10 >= data.length}>
Load More
</button>
</div>
);
};

export default PaginatedList;

In this component:

  • paginatedData is a generator function that yields pages of data.
  • Each click of the “Load More” button appends the next page of items to the items array.

When to Use Generators vs. Async/Await

While async/await is generally more popular for handling asynchronous operations, generators offer several unique benefits:

  • Control over execution flow: Generators allow you to pause execution at specific points.
  • Lazy Evaluation: Generators only calculate values when needed, which is memory-efficient for large or infinite datasets.
  • Simplifies Iteration: Generators can simplify iterating over large or complex data structures.

Generators are particularly useful for complex asynchronous flows, lazy-loading data, and handling sequences where you need fine-grained control.

--

--

Written by Frontend Highlights

This page is about simple frontend things which can be useful in real work Support us on buymeacoffee.com/guestdm or https://ko-fi.com/dm110416