Back to JavaScript
2026-03-037 min read

Generator (JavaScript)

Learn Generator (JavaScript) step by step with clear examples and exercises.

Title: Mastering Asynchronous Functions with JavaScript Generators

Why This Matters

In JavaScript, asynchronous programming is crucial for handling complex tasks such as file I/O, network requests, and time-consuming calculations without blocking the main thread. However, traditional methods like callbacks, promises, and async/await can lead to code that's hard to read, maintain, and reason about. This is where JavaScript Generators come in, offering a more elegant solution for handling asynchronous operations.

In this lesson, we will learn how to create and use generators in JavaScript, understand their benefits, and explore common mistakes to avoid when working with them. By the end of this tutorial, you'll be well-equipped to handle complex asynchronous tasks using JavaScript Generators.

Prerequisites

To follow along with this lesson, you should have a basic understanding of the following:

  • JavaScript ES6 syntax and features
  • Asynchronous programming concepts (callbacks, promises, async/await)
  • Understanding of closures and lexical scoping in JavaScript
  • Familiarity with the Fetch API or Node.js's built-in fs module for file I/O operations

Core Concept

What is a Generator?

A generator is a special type of function that can be paused and resumed during its execution. It allows you to write asynchronous code in a more elegant and readable way, similar to the synchronous counterparts. A generator function is defined using the function* keyword followed by the function name and parameters.

function* myGeneratorFunction(param1, param2) {
// Generator code here
}

The yield Keyword

The yield keyword is used to pause a generator's execution and return a value from the generator function. When a generator is called, it returns an iterator object that can be used to control its execution using the next(), throw(), and return() methods.

Generator Execution

When a generator function is called, it does not execute immediately. Instead, it creates a new iterator object that can be used to control its execution flow. The iterator object has an internal state that keeps track of the last yielded value and the line number where the generator was paused.

Generator Iteration

To iterate over a generator, you can use the next() method on its iterator object. This method resumes the generator's execution from the point it was paused, evaluates the expression after the yield keyword (if any), and returns an object with two properties: value and done. The value property contains the value yielded by the generator at that point, and the done property is a boolean indicating whether the generator has completed its execution.

Example: A Simple Generator Function

Let's create a simple generator function that yields three values:

function* myGeneratorFunction() {
yield 'Hello';
yield 'World';
yield '!';
}

const gen = myGeneratorFunction();
console.log(gen.next().value); // Hello
console.log(gen.next().value); // World
console.log(gen.next().value); // !

In this example, we create a generator function called myGeneratorFunction(), which yields the strings 'Hello', 'World', and '!'. We then create an iterator object for the generator using the assignment const gen = myGeneratorFunction();. Finally, we call the next() method on the iterator object to advance the generator's execution and log the yielded values.

Generators with Parameters

Generators can also accept parameters, just like regular functions:

function* myGeneratorFunction(param1, param2) {
yield param1;
yield param2;
}

const gen = myGeneratorFunction('Hello', 'World');
console.log(gen.next().value); // Hello
console.log(gen.next().value); // World

Generator Iteration with for...of Loop

You can iterate over a generator using the for...of loop:

function* myGeneratorFunction() {
yield 'Hello';
yield 'World';
yield '!';
}

const gen = myGeneratorFunction();
for (let value of gen) {
console.log(value);
}

In this example, we use the for...of loop to iterate over the generator's iterator object and log each yielded value.

Generators with yield*

A generator can call another generator using the yield* keyword:

function* outerGenerator() {
yield 'Outer: Start';
yield* innerGenerator();
yield 'Outer: End';
}

function* innerGenerator() {
yield 'Inner: Start';
yield 'Inner: Middle';
yield 'Inner: End';
}

const gen = outerGenerator();
console.log(gen.next().value); // Outer: Start
console.log(gen.next().value); // Inner: Start
console.log(gen.next().value); // Inner: Middle
console.log(gen.next().value); // Inner: End
console.log(gen.next().value); // Outer: End

In this example, we define two generator functions: outerGenerator() and innerGenerator(). The outerGenerator() calls the innerGenerator() using the yield* keyword, effectively merging their execution. When iterating over the outer generator's iterator object, the inner generator is executed as well.

Worked Example

Generator for Fibonacci Sequence

Let's create a generator function that yields the Fibonacci sequence starting from 0 and 1:

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

const gen = fibonacci();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3

In this example, we define a generator function called fibonacci(). Inside the function, we initialize two variables a and b to 0 and 1, respectively. We then enter an infinite loop where we yield the current value of a, update a and b, and continue the loop. This effectively generates the Fibonacci sequence indefinitely.

Common Mistakes

  1. Not returning the iterator object: When calling a generator function, make sure to assign its return value to a variable (like const gen = myGeneratorFunction();). If you forget this step, the iterator object will not be created, and you won't be able to control the generator's execution flow.
  2. Forgetting to yield values: In order for a generator to produce output, you must use the yield keyword at least once within its body. If you forget to yield any values, the generator will not produce any output when iterated over.
  3. Misusing the yield keyword: The yield keyword is used to pause a generator's execution and return a value. However, it can only be used within a generator function. If you try to use yield outside of a generator, you will encounter a syntax error.
  4. Not handling errors: Generators can throw exceptions just like regular functions. To handle these exceptions, you should wrap the generator's body in a try-catch block and catch any thrown errors. You can then yield the error object or handle it appropriately.
  5. Using generators for synchronous operations: While you can technically use generators for synchronous operations, it's generally not recommended because they add unnecessary complexity and reduce performance compared to traditional synchronous functions.

Practice Questions

  1. Create a generator function that yields the Fibonacci sequence starting from 0 and 1. Use the yield keyword to pause the execution between each number in the sequence.
  2. Write a generator function that reads lines from a file using Node.js's built-in fs module. The generator should yield each line as it is read.
  3. Implement an asynchronous function that fetches data from an API and yields the response data using a generator. Use the Fetch API to make the request.
  4. Write a generator function that generates prime numbers up to a given limit. Use the yield* keyword to call another generator function that checks if a number is prime.

FAQ

What is the difference between a regular function and a generator function in JavaScript?

A regular function executes immediately when called, while a generator function can be paused and resumed during its execution using the next(), throw(), and return() methods on its iterator object. Generators are particularly useful for handling asynchronous operations in a more elegant and readable way.

Can I use generators for synchronous operations?

While you can technically use generators for synchronous operations, it's generally not recommended because they add unnecessary complexity and reduce performance compared to traditional synchronous functions.

How do I iterate over a generator in JavaScript?

You can iterate over a generator using the next() method on its iterator object or by using the for...of loop. The next() method resumes the generator's execution and returns an object with two properties: value and done. The value property contains the value yielded by the generator at that point, and the done property is a boolean indicating whether the generator has completed its execution.

Can I call one generator function from another using the yield* keyword?

Yes, you can call one generator function from another using the yield* keyword. This allows you to effectively merge their execution and create more complex asynchronous workflows.

How do I handle errors in a generator function?

You can use try-catch blocks within your generator function to catch any exceptions that might be thrown during its execution. The caught exception can then be yielded or handled appropriately.

Generator (JavaScript) | JavaScript | XQA Learn