DEV Community

Cover image for Introduction to Generators in JavaScript
Parth Patil
Parth Patil

Posted on

Introduction to Generators in JavaScript

Generators are an advanced concept in javascript but are quite easy to understand. Generators are special functions in javascript which can return multiple values on demand unlike regular functions which can only return one value.

Unlike normal functions, the execution of a generator function can be stopped midway and can be resumed.

How to create a generator function

There is a special syntax for creating a generation function which is not much different from the normal function syntax.

function* generatorFunction(){

}
Enter fullscreen mode Exit fullscreen mode

The * after the function keyword is what makes this function a generator function.

How to use the generator function created above

Another keyword yield is introduced here. You can think of yield as the return keyword but for generator functions. Let's take an example here

function* generatorFunction(){
        console.log("Start")
        yield 7;
        console.log("Midway")
        yield 8;
        console.log("Stop")
}

const gen = generatorFunction();

let result = gen.next();
console.log(result.value) // logs 7
result = gen.next();
console.log(result.value) // logs 8
Enter fullscreen mode Exit fullscreen mode

Let's see what's happening here:

  1. We define a generator function which first yields (returns) the number 7 and then next yields the number 8. We also added a couple of console logs.
  2. We call the generatorFunction here and store the return value in the variable gen
  3. Normally when using normal functions you will expect the gen variable to hold the value 7.
  4. But that's not the case for generators. The gen variable doesn't store the value yielded by the generator, instead it stores a Generator object returned by generatorFunction
  5. The gen object has a method next()
  6. The first call of the gen.next() method starts the execution of the generator function and when it reaches a yield, it stops the function there and returns an object which has 2 properties value and done. Value is the yielded value and done is a boolean which tells us whether the generator function is done completely executing or not
  7. So in the above example, when gen.next() is called for the first time, the generator function starts executing. "Start" is logged to the console and then the generator yields a value of 7. That's when it stops the function and returns an object, which (in this case) will be { value : 7 , done : false }. value is the yielded value which is 7. done is false because the generator is not completely executed yet; there are still some lines of code in the function yet to be executed. "7" is logged to the console.
  8. The next (second) call of the gen.next() method resumes the generator function from the point it stopped at before. Thus, "Midway" is logged to the console and then the generator yields a value of 8. It stops the function there and returns { value: 8, done: false} since the yielded value is 8 and the function is still not done executing. "8" is logged to the console.
  9. "Stop" is never logged to the console since we never call gen.next() again

Notes

  • In the above example, if we call gen.next() for a third time, "Stop" will be logged on the console and the object returned would be {value : undefined, done : true}. Notice how this time the done property is true? That's because all the code of the generator is done executing. Whereas the value property is undefined? That's because no value has been yielded by the generator. If you keep calling gen.next() after this, the result will always be {value : undefined, done : true}
  • A generator object cannot be restarted. Once it's done completely executing, you cannot restart it. If you want to run a generator function again make a new Generator object by calling generatorFunction and store it in a new variable. Then you can work with that variable.

    • Example :

      const newGen = generatorFunction();
      
      const newResult = newGen.next():
      
      console.log(newResult).value) // logs 7
      

Top comments (2)

Collapse
 
mattkenefick profile image
Matt Kenefick

Here's a potential usage/implementation of a generator. This example will demonstrate how to use a generator to extract odd numbers from a list.

// Random array of numbers
const numbers = Array.from(Array(20).keys())
    .sort((a, b) => Math.random() > 0.5 ? 1.0 : -1.0);

// Generator function to find odd numbers
function* oddNumberFinder(numbers) {
    for (const i of numbers) {
        if (i % 2 === 1) {
            yield i;
        }
    }
}


// Implementation
// ----------------------------------------------

let num;
const oddNumbers = oddNumberFinder(numbers);

while (num = oddNumbers.next().value) {
    console.log('Number: ' + num);
}
Enter fullscreen mode Exit fullscreen mode

Here's a quote about generators from another language which could provide some context as to what they're for and why to use them:

"Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate."

Collapse
 
parth2412 profile image
Parth Patil

Yup. This is a good potential use. Thanks Matt