Syntax of Generator Function in JavaScript
function* functionName(){
yield1;
yield2;
//statements
return;
}
Methods of JS Generator Function
There are three methods mainly associated with generators.
- next(): It returns the value of yield.
- return(): It returns the value and then terminates the generator function.
throw(): It throws an error and then ends the generator function.
Working of Generator Function in JS
Let us see an example of a generator function and then understand its working.
Code
JS
function* generator(a) {
yield a;
yield a + 5;
}
const gen = generator(2);
console.log(gen.next().value); // expected output: 2
console.log(gen.next().value); // expected output: 7
You can also try this code with Online Javascript Compiler
Run Code
Output
2
7
Explanation
When you call a generator function, its body is not immediately executed; instead, an iterator object for the function is returned. When the iterator's next() method is invoked, the generator function's body is executed until the first yield expression, which specifies the value to be returned from the iterator or, in the case of yield*, delegates to another generator function, is reached.
The next() method produces an object that has a value property that contains the yielded value and a done property that is a boolean that indicates if the generator has yielded its last value. When you call the next() method with an argument, it will restart the execution of the generator function, substituting the yield expression that was interrupted with the argument from next ().
When a generator's return statement is invoked, the generator will end (i.e. the done property of the object returned by it will be set to true). If a value is returned, the value property of the object returned by the generator will be set to that value.
An error thrown inside the generator, similar to a return statement, will finish the generator unless it is captured within the generator's body. When a generator is completed, further next() calls will not run any of its code; instead, they will return an object of the following form: {value: undefined, done: true}.
Examples of Generator Function
Let us see some more examples of generator functions.
Example 1 - Having yield*
JS
function* anotherGenerator(a) {
yield a + 5;
yield a + 10;
yield a + 15;
}
function* generator(a) {
yield a;
yield* anotherGenerator(a);
yield a + 50;
}
var g = generator(5);
console.log(g.next().value); // Print: 5
console.log(g.next().value); // Print: 10
console.log(g.next().value); // Print: 15
console.log(g.next().value); // Print: 20
console.log(g.next().value); // Print: 55
You can also try this code with Online Javascript Compiler
Run Code
Output
5
10
15
20
55
Example 2 - Passing arguments
JS
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
var g = logGenerator();
g.next(); // 0
g.next('Coding'); // 1 Coding
g.next('Ninjas'); // 2 Ninjas
g.next('Library'); // 3 Library
You can also try this code with Online Javascript Compiler
Run Code
Output
0
1 ‘Coding’
2 ‘Ninjas’
3 ‘Library’
Example 3 - Having Return statement
JS
function* yieldAndReturn() {
yield "Yield";
return "Return";
yield "unreachable";
}
var g = yieldAndReturn();
console.log(g.next()); // { value: "Yield", done: false }
console.log(g.next()); // { value: "Return", done: true }
console.log(g.next()); // { value: undefined, done: true }
You can also try this code with Online Javascript Compiler
Run Code
Output
{value:'Yield', done: false}
{value:'Return', done: true}
{value:undefined, done: true}
Example 4 - Having Throw statement
JS
function* yieldAndThrow() {
yield 50;
yield 70;
}
var g = yieldAndThrow();
console.log(g.next());
console.log(g.throw(new Error('An error found!!!')));
console.log(g.next());
You can also try this code with Online Javascript Compiler
Run Code
Output
{value:50, done: false}
yield 50;
^
Error: An error found!!!
Example 5 - Generator example
JS
function* powers(i){
//infinite loop to calculate exponent
for(let curr =i ; ; curr *= i){
yield curr;
}
}
for(let power of powers(2)){
//controlling generator
if(power > 64) break;
console.log(power)
}
You can also try this code with Online Javascript Compiler
Run Code
Output
2
4
8
16
32
64
For better understanding try it on an online javascript editor.
How to Throw an Exception from a Generator Object?
In JavaScript, you can throw an exception from a generator object using the throw method. This method can be called on a generator to signal an error and can also be caught within the generator itself using a try-catch block. Below is a detailed explanation along with code implementation, expected output, and explanation.
JS
function* generatorFunction() {
try {
// Yield a value
const value = yield "Generator started";
console.log("Received:", value);
} catch (error) {
// Catch the thrown error
console.log("Caught an error:", error.message);
}
}
const gen = generatorFunction();
// Start the generator
console.log(gen.next().value); // Output: "Generator started"
// Throw an exception into the generator
gen.throw(new Error("Something went wrong")); // Output: "Caught an error: Something went wrong"
You can also try this code with Online Javascript Compiler
Run Code
Output
Generator started
Caught an error: Something went wrong
Advantages of using the Generator Function
The advantages of using generator functions are:
- Lazy Evaluation: This is an evaluation paradigm that waits until the value of an expression is required before evaluating it. In other words, if the value isn't needed, it won't exist. It is based on demand.
- Efficient Memory: Generators are memory efficient as a direct result of Lazy Evaluation. Only the values that are required are created. All of the values for typical functions must be pre-generated and saved in case they are needed later. With generators, however, the calculation is postponed.
Disadvantages of Generator Function
Here are some disadvantages of generator functions in JavaScript:
- Single Iteration: Generators can only be iterated once. Once a generator's execution is complete, it cannot be restarted or reused, which may require additional logic to handle repeated iterations over the same sequence of values.
- Complexity in Error Handling: While generators can handle exceptions internally, managing errors and control flow across multiple yield points can complicate code readability and maintainability, especially in larger applications.
- Performance Overhead: Using generators may introduce some performance overhead compared to traditional functions, particularly for simple operations, due to the context switching and state management involved in yielding and resuming execution.
Frequently Asked Questions
Define generator object.
A generator object is returned by generator functions. Calling the next method on the generator object or utilising the generator object in a "for of" loop are two ways to use generator objects. A generating function returns the Generator object, which is compliant with both the iterable and iterator protocols.
Describe yield and yield*.
- yield: stops the generator from running and returns the value of the expression written after the yield keyword.
- yield*: iterates through the operands, returning each value until done is true.
When should I use generators in JavaScript?
Generators should be used when managing asynchronous operations, such as fetching data in sequence or implementing complex iterators. They provide better control over the execution flow and allow yielding values on demand, improving code readability.
What is the difference between a generator function and a normal function in JavaScript?
A generator function can pause execution and yield multiple values over time, using the yield keyword, while a normal function executes entirely and returns a single value. Generators return an iterator that allows for stateful iteration.
Why do we need a generator function?
Generator functions are useful for creating iterators that can produce a sequence of values lazily, improving performance and memory efficiency. They simplify asynchronous programming patterns and allow for more elegant handling of complex workflows without blocking the main thread.
Conclusion
In this article, we learned about the Generator Function in JavaScript. Generator functions in JavaScript provide a powerful tool for managing asynchronous operations and creating custom iterators. By enabling the ability to pause and resume execution, they offer a more flexible and efficient approach to handling sequences of data. Generators enhance code readability and maintainability, especially when dealing with complex workflows or large datasets.
Recomended Articles