The Wayback Machine - https://web.archive.org/web/20241218120823/https://www.geeksforgeeks.org/javascript-function-generator/
Open In App

JavaScript Function Generator

Last Updated : 12 Dec, 2024
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Save
Share
Report
News Follow

A generator function is a special type of function that can pause its execution at any point and resume later. They are defined using the function* syntax and use the yield keyword to pause execution and return a value.

JavaScript
function* generatorFunction() {
    yield 'Hello';
    yield 'World';
    return 'Done';
}

const generator = generatorFunction();

console.log(generator.next());
console.log(generator.next()); 
console.log(generator.next());
console.log(generator.next()); 

Output
{ value: 'Hello', done: false }
{ value: 'World', done: false }
{ value: 'Done', done: true }
{ value: undefined, done: true }

Key Features of Generators:

  • Pause and Resume: Generators allow pausing function execution using yield and resuming it with the next() method.
  • Iterable Interface: They return an iterator that conforms to the iterable protocol.
  • Asynchronous Support: Ideal for working with asynchronous tasks using for-await-of loops.

Syntax of Generator Functions

The syntax for defining a generator function is slightly different from regular functions. Use an asterisk (*) after the function keyword.

How Do Generators Work?

  • Creating a Generator: Call the generator function to create a generator object.
  • Using the next() Method: The next() method moves the generator to the next yield statement, returning an object with value and done properties.
  • value: The value yielded by the generator.
  • done: A boolean indicating whether the generator has completed execution.
JavaScript
function* countUpTo(max) {
    let count = 1;
    while (count <= max) {
        yield count++;
    }
}
const counter = countUpTo(3);
console.log(counter.next()); 
console.log(counter.next()); 
console.log(counter.next());
console.log(counter.next());

Output
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }

Use Cases for Generators

1. Custom Iterators

Generators simplify the creation of custom iterators, making it easy to generate sequences of values.

JavaScript
function* fibonacci(limit) {
    let [prev, current] = [0, 1];
    while (limit--) {
        yield current;
        [prev, current] = [current, prev + current];
    }
}
const fib = fibonacci(5);
console.log([...fib]); 

Output
[ 1, 1, 2, 3, 5 ]

2. Asynchronous Programming

Generators, in combination with libraries like co or with async/await syntax, help manage asynchronous flows.

JavaScript
function* asyncTask() {
    console.log('Task 1');
    yield new Promise(resolve => setTimeout(() => resolve('Task 2'), 1000));
    console.log('Task 3');
}
const task = asyncTask();
task.next().value.then(console.log); 
task.next(); 

Output:

Task 1
Task 3
Task 2

3. Infinite Sequences

Generators can create infinite sequences that only compute values on demand.

JavaScript
function* infiniteSequence() {
    let i = 0;
    while (true) {
        yield i++;
    }
}
const sequence = infiniteSequence();
console.log(sequence.next().value); 
console.log(sequence.next().value); 
console.log(sequence.next().value); 

Output
0
1
2

Advantages of Generator Functions

  • Lazy Evaluation: Values are computed only when needed, improving performance for large or infinite sequences.
  • Readable Asynchronous Code: Generators can make asynchronous workflows look synchronous, simplifying complex code.
  • Modularity: Encapsulate logic for producing sequences or iterating over data within a generator.
  • Customizable Iterators: Generators allow creating iterators without implementing the entire iterable protocol manually.

Limitations of Generator Functions

  • Complexity: Understanding and debugging generator-based code can be challenging for beginners.
  • Not Fully Asynchronous: While useful, generators alone are not a replacement for promises or async/await in handling asynchronous programming.

Best Practices

  • Use Meaningful Names: Clearly name your generator functions to describe their behavior.
  • Handle Edge Cases: Ensure your generator logic handles termination and invalid inputs gracefully.
  • Leverage Iteration Utilities: Combine generators with utilities like Array.from, spread syntax, or for-of loops to maximize their potential.


Next Article

Similar Reads

Article Tags :
three90RightbarBannerImg