How to Use Generator and yield in JavaScript
Tags: javascript, node, programming, typescript
Published: 2020-06-17 20:58:06

---
title: How to Use Generator and yield in JavaScript
published: true
date: 2020-06-17 08:51:01 UTC
cover_image: https://livecodestream.dev/post/2020-06-17-how-to-use-generator-and-yield-in-javascript/featured.jpg
tags: ["Javascript", "NodeJS", "Programming", "Typescript"]
canonical_url: http://livecodestream.dev/post/2020-06-17-how-to-use-generator-and-yield-in-javascript/
---

Some time ago I wrote an article explaining the concept of [generators and how to use them in Python](/post/2020-06-01-how-to-use-generator-and-yield-in-python/), but did you know that JavaScript has its own version of generators? This is actually a concept many people who develop JavaScript apps didn't know it existed, so today we are going to introduce generators in JavaScript. 

---

## What are generators?
With ES6 we got introduced to great new functionality like [arrow functions](/post/2020-05-22-when-not-to-use-javascript-arrow-functions/), [spread operators](/post/2020-05-23-how-to-use-the-spread-operator-in-javascript/), and generators among others, but what is a generator? A generator is a function that contrary to normal functions allows for the function to be exited and later re-entered with its context (variable bindings) preserved across re-entrances.

Let's break that down and look into generators step by step so that we can all understand how they work. When we execute a regular function, the interpreter will run all the code into that function until the function is completed (or throws an error). This is known as the **run-to-completion** model.

Let's take an example of a very simple function:

```javascript
function regularFunction() {
    console.log("I'm a regular function")
    console.log("Surprise surprice")
    console.log("This is the end")
}

regularFunction()

-----------------
Output
-----------------
I'm a regular function
Surprise surprice
This is the end
```

Nothing fancy yet, just as you expected is a regular function that's executing until it reaches the end or returns a value. But what if we just want to stop the function at any point to return a value, and then continue? That's when generators enter the picture.

### My first generator function

```javascript
function* generatorFunction() {
    yield "This is the first return"
    console.log("First log!")
    yield "This is the second return"
    console.log("Second log!")
    return "Done!"
}
```

Before we execute that function you may be wondering about a few things, first what is `function*`? That's the syntax we use to declare a function as a generator. And what about `yield`? The `yield`, in difference to a return, will pause the function by saving all its states and will later continue from that point on successive calls. In both cases, the expression will be returned to the callers' execution.

What did exactly happened to our function as such? Let's find out by calling the function:

```javascript
generatorFunction()

-----------------
Output
-----------------
generatorFunction {<suspended>} {
    __proto__: Generator
    [[GeneratorLocation]]: VM272:1
    [[GeneratorStatus]]: "suspended"
    [[GeneratorFunction]]: ƒ* generatorFunction()
    [[GeneratorReceiver]]: Window
    [[Scopes]]: Scopes[3]
}
```

Wait, what? When we call a generator function the function is not automatically triggered and instead, it returns an iterator object. What's particular about this object is that when the method next() is called, the generator function's body is executed until the first `yield` or `return` expression. Let's see it in action:

```javascript
const myGenerator = generatorFunction()
myGenerator.next()

-----------------
Output
-----------------
{value: "This is the first return", done: false}
```

As explained the generator run until the first `yield` statement and yielded an object containing a `value` property, and a `done` property.

```javascript
{ value: ..., done: ... }
```

- The `value` property is equal to the value that we yielded
- The `done` property is a boolean value, which is only set to `true` once the generator function returned a value. (not yielded)

Let's invoke `next()` one more time and see what we get

```javascript
myGenerator.next()

-----------------
Output
-----------------
First log!
{value: "This is the second return", done: false}
```

This time we first see the `console.log` in our generator body being executed and printing `First log!`, and the second yielded object. And we could continue doing this like:

```javascript
myGenerator.next()

-----------------
Output
-----------------
Second log!
{value: "Done!", done: true}
```

Now the second `console.log` statement is executed and we get a new returned object, but this time the property `done` is set to `true`.

The value of the `done` property is not just a flag, it is a very important flag as **we can only iterate a generator object once!**. Don't believe me? try calling `next()` one more time:

```javascript
myGenerator.next()

-----------------
Output
-----------------
{value: undefined, done: true}
```

Good it didn't crash, but we only got undefined as the `value` and the `done` property remains set to true.

### Yielding over iterators
Before we move on to some scenarios, there's one more particularity of the yield operator, which is `yield*`. Let's explain it by creating a function that allows us to iterate over an array, naively we could think of doing:

```javascript
function* yieldArray(arr) {
    yield arr
}

const myArrayGenerator1 = yieldArray([1, 2, 3])
myArrayGenerator1.next()

-----------------
Output
-----------------
{value: Array(3), done: false}
```

But that's not quite what we wanted, we wanted to yield each element in the array, so we could try doing something like:

```javascript
function* yieldArray(arr) {
    for (element of arr) {
        yield element
    }
}

const myArrayGenerator2 = yieldArray([1, 2, 3])
myArrayGenerator2.next()
myArrayGenerator2.next()
myArrayGenerator2.next()

-----------------
Output
-----------------
{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
```

Now we got the desired result, but can we do better? Yes, we can:

```javascript
function* yieldArray(arr) {
    yield* arr
}

const myArrayGenerator3 = yieldArray([1, 2, 3])
myArrayGenerator3.next()
myArrayGenerator3.next()
myArrayGenerator3.next()

-----------------
Output
-----------------
{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
```

Awesome, by using yield* expression we can iterate over the operand and yield each value returned by it. This applies to other generators, arrays, strings, any iterable object.

Now that you know all about generators in JavaScript, what are they good for?

---

## Uses of Generators
The great thing about generators is the fact that they are lazy evaluated, meaning that the value that gets returned after invoking the `next()` method, is only computed after we specifically asked for it. This makes generators a good choice for solving multiple scenarios like the ones presented below.

### Generating an infinite sequence
As we saw in the Python article, generators are good for generating infinite sequences, this could be anything from prime numbers to a simple count:

```javascript
function* infiniteSequence() {
    let num = 0
    while (true) {
        yield num
        num += 1
    }
}

for(i of infiniteSequence()) {
    if (i >= 10) {
        break
    }
    console.log(i)
}

-----------------
Output
-----------------
0
1
2
3
4
5
6
7
8
9
```

Note that in this case, I'm exiting the loop when `i >= 10` otherwise, it would be running forever (or until manually stopped).

### Implementing iterables
When you need to implement an iterator, you have to manually create an object with a `next()` method. Also, you have to manually save the state.

Imagine we want to make an iterable that simply returns `I`, `am`, `iterable`. Without using generators we would have to do something like:
 
```javascript
const iterableObj = {
  [Symbol.iterator]() {
    let step = 0;
    return {
      next() {
        step++;
        if (step === 1) {
          return { value: 'I', done: false};
        } else if (step === 2) {
          return { value: 'am', done: false};
        } else if (step === 3) {
          return { value: 'iterable.', done: false};
        }
        return { value: '', done: true };
      }
    }
  },
}
for (const val of iterableObj) {
  console.log(val);
}

-----------------
Output
-----------------
I
am
iterable.
```

With generators this is much simpler:

```javascript
function* iterableObj() {
    yield 'I'
    yield 'am'
    yield 'iterable.'
}

for (const val of iterableObj()) {
  console.log(val);
}

-----------------
Output
-----------------
I
am
iterable.
```

### Better Async?
Some argue generators can help improve the use of promises and callbacks, though I'd preferably simply use await/async.

---

## Caveats
Not all is shiny when we work with generators. There are some limitations by design, and there are 2 very important considerations:

- Generator objects are one-time access only. Once exhausted, you can't iterate over it again. To do so, you will have to create a new generator object.
- Generator objects do not allow random access as possible with for instance, arrays. Since the values are generated one by one, you can't get the value for a specific index, you will have to manually call all the `next()` functions until you get to the desire position, but then, you cannot access the previously generated elements.

---

## Conclusion
Generator functions are great for optimizing the performance of our applications and also help to simplify the code required to build iterators.

I hope you now have a good understanding of generators in JavaScript and that you can use them on your next project.

Thanks for reading!

* * *

If you like the story, please don't forget to subscribe to our free newsletter so we can stay connected: [https://livecodestream.dev/subscribe](https://livecodestream.dev/subscribe)