Understanding JavaScript Generator Functions and Yield Operations
Add to your RSS feed17 February 20254 min read
Table of Contents
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
1 // Regular function2 function normalFunction() {3 return "Hello, World!";4 }56 console.log(normalFunction()); // Output: "Hello, World!"78 // Generator function9 function* simpleGenerator() {10 yield "Hello";11 yield "World";12 }1314 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
1 function* numberGenerator() {2 yield 1;3 yield 2;4 yield 3;5 }
2. Function Expression
1 const wordGenerator = function* () {2 yield "Hello";3 yield "World";4 };
3. Generator as an Object Method
1 const obj = {2 *charGenerator() {3 yield "A";4 yield "B";5 }6 };
4. Generator in a Class
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.
1 function* simpleCounter() {2 yield 1;3 yield 2;4 return 3;5 }67 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
1 function* countdown(start) {2 while (start > 0) {3 yield start--;4 }5 return "Done!";6 }78 const timer = countdown(5);9 console.log(timer.next().value); // 510 console.log(timer.next().value); // 411 console.log(timer.next().value); // 3
2. Infinite Number Sequence
1 function* infiniteNumbers(start = 1) {2 let num = start;3 while (true) {4 yield num++;5 }6 }78 const numGen = infiniteNumbers();9 console.log(numGen.next().value); // 110 console.log(numGen.next().value); // 211 console.log(numGen.next().value); // 3
3. Fibonacci Sequence
1 function* fibonacci() {2 let [prev, curr] = [0, 1];3 while (true) {4 yield prev;5 [prev, curr] = [curr, prev + curr];6 }7 }89 const fibGen = fibonacci();10 console.log(fibGen.next().value); // 011 console.log(fibGen.next().value); // 112 console.log(fibGen.next().value); // 113 console.log(fibGen.next().value); // 2
4. Paginated Data Fetching
1 function* paginate(array, size) {2 for (let i = 0; i < array.length; i += size) {3 yield array.slice(i, i + size);4 }5 }67 const items = [10, 20, 30, 40, 50, 60];8 const pages = paginate(items, 2);910 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.
1 function* mathOperations() {2 const a = yield "Enter first number";3 const b = yield "Enter second number";4 return `Sum: ${a + b}`;5 }67 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
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 }910 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()
)
1 function* countDown(n) {2 while (n > 0) {3 yield n--;4 }5 return "Finished!";6 }78 const counter = countDown(3);9 console.log(counter.next().value); // 310 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*
)
1 function* subGenerator() {2 yield "Sub-task 1";3 yield "Sub-task 2";4 }56 function* mainGenerator() {7 yield "Main task";8 yield* subGenerator();9 yield "Main task resumed";10 }1112 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. 🚀