JavaScript Development Space

Understanding JavaScript Generator Functions and Yield Operations

Add to your RSS feed17 February 20254 min read
JavaScript Generators: A Complete Guide to Yield and Iterators

Generators are special functions in JavaScript that return an iterator and allow execution to be paused using the yield keyword. Unlike regular functions that run to completion when called, generators can be paused and resumed, making them useful for lazy execution and handling large datasets.

Basic Function vs Generator

js
1 // Regular function
2 function normalFunction() {
3 return "Hello, World!";
4 }
5
6 console.log(normalFunction()); // Output: "Hello, World!"
7
8 // Generator function
9 function* simpleGenerator() {
10 yield "Hello";
11 yield "World";
12 }
13
14 const iterator = simpleGenerator();
15 console.log(iterator.next().value); // Output: "Hello"
16 console.log(iterator.next().value); // Output: "World"
17 console.log(iterator.next().done); // Output: true

Generators return values step by step, making them ideal for handling large or streaming data without consuming too much memory.

Why Use Generators?

  • Lazy Execution: Code runs only when needed.
  • Better Readability & Maintainability: Helps manage complex stateful logic.
  • Efficient Data Handling: Useful for processing large datasets or infinite sequences.

Generator Syntax

A generator function is declared with an asterisk (*) after the function keyword. Instead of returning a value immediately, it uses yield to pause execution.

Ways to Define a Generator

1. Function Declaration

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

2. Function Expression

js
1 const wordGenerator = function* () {
2 yield "Hello";
3 yield "World";
4 };

3. Generator as an Object Method

js
1 const obj = {
2 *charGenerator() {
3 yield "A";
4 yield "B";
5 }
6 };

4. Generator in a Class

js
1 class GeneratorClass {
2 *stringGenerator() {
3 yield "X";
4 yield "Y";
5 }
6 }

How Generators Work

Generators execute step by step and pause at each yield statement. The execution resumes when next() is called.

js
1 function* simpleCounter() {
2 yield 1;
3 yield 2;
4 return 3;
5 }
6
7 const counter = simpleCounter();
8 console.log(counter.next()); // { value: 1, done: false }
9 console.log(counter.next()); // { value: 2, done: false }
10 console.log(counter.next()); // { value: 3, done: true }
11 console.log(counter.next()); // { value: undefined, done: true }

Understanding next() Method

  • value: The yielded value.
  • done: Boolean indicating whether the generator is finished.

Practical Use Cases

Generators shine in scenarios requiring step-by-step execution, state retention, or lazy evaluation.

1. Countdown Timer

js
1 function* countdown(start) {
2 while (start > 0) {
3 yield start--;
4 }
5 return "Done!";
6 }
7
8 const timer = countdown(5);
9 console.log(timer.next().value); // 5
10 console.log(timer.next().value); // 4
11 console.log(timer.next().value); // 3

2. Infinite Number Sequence

js
1 function* infiniteNumbers(start = 1) {
2 let num = start;
3 while (true) {
4 yield num++;
5 }
6 }
7
8 const numGen = infiniteNumbers();
9 console.log(numGen.next().value); // 1
10 console.log(numGen.next().value); // 2
11 console.log(numGen.next().value); // 3

3. Fibonacci Sequence

js
1 function* fibonacci() {
2 let [prev, curr] = [0, 1];
3 while (true) {
4 yield prev;
5 [prev, curr] = [curr, prev + curr];
6 }
7 }
8
9 const fibGen = fibonacci();
10 console.log(fibGen.next().value); // 0
11 console.log(fibGen.next().value); // 1
12 console.log(fibGen.next().value); // 1
13 console.log(fibGen.next().value); // 2

4. Paginated Data Fetching

js
1 function* paginate(array, size) {
2 for (let i = 0; i < array.length; i += size) {
3 yield array.slice(i, i + size);
4 }
5 }
6
7 const items = [10, 20, 30, 40, 50, 60];
8 const pages = paginate(items, 2);
9
10 console.log(pages.next().value); // [10, 20]
11 console.log(pages.next().value); // [30, 40]
12 console.log(pages.next().value); // [50, 60]

Advanced Generator Features

Generators also support advanced interactions such as bidirectional communication and exception handling.

1. Sending Values to Generators (next(value))

Values can be sent into a generator, which becomes the result of the last yield statement.

js
1 function* mathOperations() {
2 const a = yield "Enter first number";
3 const b = yield "Enter second number";
4 return `Sum: ${a + b}`;
5 }
6
7 const mathGen = mathOperations();
8 console.log(mathGen.next().value); // "Enter first number"
9 console.log(mathGen.next(5).value); // "Enter second number"
10 console.log(mathGen.next(10).value); // "Sum: 15"

2. Handling Errors in Generators

js
1 function* errorHandlingGen() {
2 try {
3 yield "Step 1";
4 yield "Step 2";
5 } catch (err) {
6 console.log("Caught error:", err.message);
7 }
8 }
9
10 const errGen = errorHandlingGen();
11 console.log(errGen.next().value); // "Step 1"
12 errGen.throw(new Error("Something went wrong")); // "Caught error: Something went wrong"
13 console.log(errGen.next().done); // true

3. Prematurely Stopping a Generator (return())

js
1 function* countDown(n) {
2 while (n > 0) {
3 yield n--;
4 }
5 return "Finished!";
6 }
7
8 const counter = countDown(3);
9 console.log(counter.next().value); // 3
10 console.log(counter.return("Stopped early").value); // "Stopped early"
11 console.log(counter.next()); // { value: undefined, done: true }

4. Delegating Execution to Another Generator (yield*)

js
1 function* subGenerator() {
2 yield "Sub-task 1";
3 yield "Sub-task 2";
4 }
5
6 function* mainGenerator() {
7 yield "Main task";
8 yield* subGenerator();
9 yield "Main task resumed";
10 }
11
12 const task = mainGenerator();
13 console.log([...task]);
14 // ["Main task", "Sub-task 1", "Sub-task 2", "Main task resumed"]

Conclusion

Generators are a powerful tool in JavaScript for handling sequences, stateful logic, and lazy computations. They provide greater control over execution flow and are especially useful in scenarios like:

  • Iterating over large datasets efficiently
  • Generating infinite sequences
  • Managing asynchronous flows
  • Handling complex logic in a readable way

By leveraging advanced generator features like yield*, next(value), throw(), and return(), you can write cleaner, more efficient code. 🚀

JavaScript Development Space

© 2025 JavaScript Development Space - Master JS and NodeJS. All rights reserved.