Everything you need to know about Generators in JavaScript 🚀
Tags: javascript, webdev, programming, beginners
Published: 2022-06-26 08:14:15

---
title: Everything you need to know about Generators in JavaScript 🚀
published: true
date: 2022-06-25 17:11:19 UTC
tags: 
canonical_url: https://thecodingcookbook.hashnode.dev/everything-you-need-to-know-about-generators-in-javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ignmaotlspm4epugl440.png
tags: javascript, webdev, programming, beginners
---

If you have been working with JavaScript quite a lot, you might have come across some syntax like this:

```
function* makeIterator() {
    yield 1;
    yield 2;
}
```

Now, you might be wondering what is this code exactly doing? Well, honestly speaking, I felt the same when I came across such syntax for the first time! 😅

![I don't understand](https://media.giphy.com/media/ne3xrYlWtQFtC/giphy.gif)

This weird yet quite useful piece of code is what we call **Generators** in JavaScript.

Let's try and understand what are Generators, how to use them, and when to use them in your JavaScript code.

## Demystifying Iterators & Generators

Now, before we try to understand generators, let's first understand the concept of **Iterables** and **Iterators** so that we can understand generators better.

**Iterables** : Iterables are basically **data structures** that have the `Symbol.iterator()` method or the `Symbol.iterator` key. Some of the most commonly used data structures in JavaScript like Array, String, Set, and Map are examples of Iterables.

The `Symbol.iterator()` method defines how these iterables can be iterated by using iterators and the `for...of` loop.

**Iterators** : An iterator is an object that is returned by the `Symbol.iterator()` method. This object has a `next()` method that returns an object with two properties:

`value`: The value of the next element in the iteration sequence or the iterable.   
`done`: This is a boolean value. It is set to `true` if the last element in the iteration sequence is already iterated else it is set to `false`.

Let's see a simple example of how we can iterate through all the elements in the Array using a `for...of` loop and an Array Iterator.

```
const number = [1, 2, 3];
const arrayIterator = number[Symbol.iterator]();

console.log(arrayIterator);

// Iterating through the iterator to access array elements
for (let n of arrayIterator) {
    console.log(n);
}
```

**Output** :

```
Array Iterator {}
1
2
3
```

### So, what are generators?

A generator is a process that can be paused and resumed and can yield multiple values. A generator in JavaScript consists of a Generator function, which returns an iterable `Generator` object and this object is basically a special type of Iterator.

### Now, what are generator functions?

Let's have a look at a simple example of a generator function to understand it better.

```
// Generator function declaration
function* generatorFunction() {}
```

As you can see above, a Generator function can be defined by using the `function` keyword followed by an asterisk (`*`). Occasionally, you will also see the asterisk next to the function name, as opposed to the function keyword, such as `function *generatorFunction()`. This works the same, but `function*` is generally a more widely accepted syntax.

Generator functions can also be defined in regular function expressions:

```
// Generator function expression
const generatorFunction = function*() {}
```

### Why do we need to use Generators?

We can define our own custom iterators for our specific use cases, so why should we even care about generators at all?

There's an added complexity with **custom iterators** that you have to carefully program them and also **explicitly maintain their internal state** to know which elements have been iterated and when to stop the function execution.

Generators provide a powerful alternative to custom iterators that allows you to define your own iteration algorithms using generator functions that do not execute code continuously.

![Powerful Generators!](https://media.giphy.com/media/RN6OnheJ9ZEm4/giphy.gif)

Let's look at how you can use these Generator functions & Generators for your specific use cases.

## Working with Generator functions & Generators

A generator function, when invoked, returns an iterable `Generator` object which is basically nothing but a generator. A generator function differs from a traditional function JavaScript in that generator functions do not return a value immediately instead they return a `Generator` object which is an iterator as we saw above.

Let's have a look at an example to make this difference between generator functions and traditional functions clear.

In the following code, we create a simple `power()` function that calculates the **power of a given number** by using **two integer parameters** ( **base no** and the **exponent no** ) and returns this calculated value.

```
// A regular function that calculates power of a no
function power(base, exponent) {
  return Math.pow(base, exponent);
}
```

Now, calling this function returns the power of the given no,

```
power(2, 3); // 8
```

Now, let's create the same function above but as a generator function,

```
// A generator function that calculates power of a no
function* powerGeneratorFunction(base, exponent) {
  return Math.pow(base, exponent);
}

const powerGenerator = power(2, 3);
```

Now, when we invoke the generator function, it will return the `Generator` object which looks something like this,

```
power {<suspended>}
[[GeneratorLocation]]: VM305:2
[[Prototype]]: Generator
[[GeneratorState]]: "suspended"
[[GeneratorFunction]]: * power(base, exponent)
[[GeneratorReceiver]]: Window
[[Scopes]]: Scopes[3]
```

This `Generator` object has a `next()` method similar to Iterators. Let's call this method and see what we get,

```
// Call the next method on the Generator object
powerGenerator.next();
```

This will give the following output:

```
{ value: 8, done: true }
```

As we saw earlier, a `Generator` object is nothing but an Iterator, hence the `next()` method returns something similar to Iterators i.e an object containing two properties, `value` & `done`. The power of `2` raised to `3` is `8` which is reflected by `value`. The value of `done` is set to `true` because this value came from a `return` that closed out this generator.

We saw how to create a simple generator function and how these functions work. Now let's have a look at some of the features of these generators that make them quite useful and unique.

### The `yield` operator

Generators introduce a new keyword to JavaScript: `yield`. The `yield` operator can pause a generator function and return the value that follows `yield`, providing a lightweight way to iterate through values.

Let's have a look at an example to understand this better.

```
function* simpleGeneratorFunction () {
  console.log("Before 1");
  yield 1;
  console.log("After 1");
  console.log("Before 2");
  yield 2;
  console.log("After 2");
  console.log("Before 3");
  yield 3;
  console.log("After 3");
}

const simpleGenerator = simpleGeneratorFunction();
```

In the above code snippet, we have defined a simple generator function that contains 3 `yield` statements. Now, let's call the `next()` method to see how this `yield` operator works.

```
// Call the next() method four times
console.log(simpleGenerator.next());
console.log(simpleGenerator.next());
console.log(simpleGenerator.next());
console.log(simpleGenerator.next());
```

Now, when we call `next()` on the generator function, it will pause every time it encounters `yield`. The `done` property will be set to `false` after each `yield`, indicating that the generator has not finished. Once we encounter a `return` statement or if there are no more `yield` statements left, then the `done` property will be set to `true`.

Let's look at the output after calling the `next()` method **four** times.

```
Before 1
{value: 1, done: false}
After 1
Before 2
{value: 2, done: false}
After 2
Before 3
{value: 3, done: false}
After 3
{value: undefined, done: true}
```

### Iterating Over a Generator

Using the `next()` method, we manually iterated through the `Generator` object, receiving all the `value` and `done` properties of the full object. We can iterate over a generator similar to how we can iterate over data structures like `Array`, `Map`, or `Set` using a simple `for...of` loop.

Let's have a look at the above example and see how we can iterate over generators.

```
// Creating a new Generator object.
const newGenerator = simpleGeneratorFunction();

// Iterating over the Generator object
for (const value of newGenerator) {
  console.log(value);
}
```

> **Note** : In the above code snippet, we initialized a new `Generator` object as we had already manually iterated the older `Generator` object & hence it can't be iterated again.

This code snippet now returns the following output,

```
Before 1
1
After 1
Before 2
2
After 2
Before 3
3
After 3
```

As you can see, we iterated through all the values of the `Generator` object. Now, let's look at some of the use-cases of Generators and Generator functions.

### Passing values in Generators

Generators provide a way to pass custom values through the `next()` method of the `Generator` object to modify the internal state of the generator.

> **Note** : A value passed to `next()` will be received by the `yield` operator.

Let's take an example to understand this better.

```
// Take three integers and return their sum
function* sumGeneratorFunction() {
  let sumOfThreeNos = 0;
  console.log(sumOfThreeNos);
  sumOfThreeNos += yield;
  console.log(sumOfThreeNos);
  sumOfThreeNos += yield;
  console.log(sumOfThreeNos);
  sumOfThreeNos += yield;
  console.log(sumOfThreeNos);

  return sumOfThreeNos;
}

const generator = sumGeneratorFunction();

generator.next();
generator.next(100);
generator.next(200);
generator.next(300);
```

This will give the following output:

```
0
100
300
600
{value: 600, done: true}
```

In the above example, we are calculating the cumulative sum of three nos by passing them one by one by passing the value in the `next()` method.

> **Note** : Passing a value to the first `next()` method has no effect on the internal state of the generator. Values can be passed from the 2nd call to all the other subsequent calls to this method.

## Uses of Generators and Generator functions

Generators and Generator functions are quite powerful and have some really good use-cases.

![Power of Generators](https://media.giphy.com/media/A9grgCQ0Dm012/giphy-downsized-large.gif)

- Generators provide a great way of making iterators and are capable of dealing with infinite data streams, which can be used to implement infinite scroll on the Front-End of a web application. 

- Generators when used with `Promise` can be used to simulate `async/await` functionality in JS to allow handling more advanced use-cases while dealing with APIs or asynchronous code. It allows us to work with asynchronous code in a simpler and more readable manner.

- Generators are also internally used in some of the NPM libraries to provide a custom way for the developer to iterate through some of the objects/data structures implemented by the library. They are also used for internal asynchronous operations to handle more advanced use cases.

Let's discuss one of the major use-cases of Generators that you will most likely come across i.e dealing with **infinite iterations**.

To demonstrate infinite streams, we consider a simple square number series in Mathematics where each term in the series can be calculated by a simple formula: `n^2`. Let's create a generator function for this series by creating an infinite loop as follows:

```
// Create a square number series generator function
function* squareNumberSeries() {
  let n = 1;

  // Square the no and increment it to yield the infinite series
  while (true) {
    const squaredNo = Math.pow(n, 2);
    yield squaredNo;
    n += 1;
  }
}
```

To test this out, we can loop through a finite number and print the Square number sequence to the console.

```
// Print the first 10 values of the square number series
const squareNoGenerator = squareNumberSeries();

for (let i = 0; i < 10; i++) {
  console.log(squareNoGenerator.next().value);
}
```

This will generate the following series:

```
1
4
9
16
25
36
49
64
81
100
```

The `squareNumberSeries` generator function in the above code snippet returns successive values in the infinite loop while the `done` property remains false, ensuring that it will not finish. With generators, we dont need to worry about creating an infinite loop, because we can halt and resume its execution at will.

However, we still have to take care with how we invoke the generator.

> Using the spread operator or `for...of` loop on an infinite data stream will cause it to keep iterating over an infinite loop all at once, which will cause the environment to crash.

Working with infinite data streams is one of the most powerful features that generators provide without worrying about managing all the internal states for a custom iterator implementation.

## Conclusion

They are a powerful, versatile feature of JavaScript, although they are not commonly used. In this article, we got a brief overview of what are iterators and generators, what are generator functions, why we need to use generators, and finally how to work with generators and generator functions. We also discussed a very powerful use case of generators for dealing with infinite data streams.

That's it from me folks, thank you so much for reading this blog! 🙌 I hope I was able to make generators interesting for you and was able to give a brief overview of them through this blog 😄

Last but not the least, ![You folks are awesome!](https://media.giphy.com/media/tEaDT85En43i8/giphy.gif)

> Feel free to reach out to me:
> [Twitter](https://twitter.com/DevanshYtweets)
> [Linkedin](https://www.linkedin.com/in/devansu-yadav/)
> [GitHub](https://github.com/Devansu-Yadav)
> You can also reach out to me over mail: [devansuyadav@gmail.com](mailto:devansuyadav@gmail.com)