How to go from just using async await to understanding what is going on under the hood.

Why even learn how async await works?

This knowledge may be of good use in mid level to senior level interviews.

It helps us stay up to date and know the building blocks of upcoming features in JavaScript.

Requirements to get the best out of this article:

Knowledge of how Promises and Iterators work in JavaScript.

Desire to know and master JavaScript.

JavaScript Generator Functions:

Wait a minute…. I thought this post was about async await, not generator functions?

Well you see, async await is built on top of generator functions.

The developer Mozilla website states this:

Generators in JavaScript — especially when combined with Promises — are a very powerful tool for asynchronous programming as they mitigate — if not entirely eliminate — the problems with callbacks, such as Callback Hell and Inversion of Control.

This pattern is what Async functions are built on top of.

Well, what exactly are generators? Once again let’s check what the Mozilla docs have to say.

Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.

Let’s build quick generator function and make some observations:

Let’s walk line by line though the code above.

Line 1 — we have a generator function declaration named simpleGenerator. We know it’s a generator function because it has the ‘*’ after the function keyword. The ‘*’ is a requirement. Line 6 — we have a variable declaration named gen, which is assigned the result of the execution of simpleGenerator function. This is where it gets interesting. Unlike other functions that, once executed, start a new local execution context, a generator function returns a generator object. The generator object has a next property. This property is a function which will return an object with two properties. If you are familiar with iterators in Javascript you will be familiar with these two properties. The first is a value property, which will have the value of whatever is yielded during that particular execution; the second property is called done, which has a boolean value. Line 8 — we have a const variable declaration named firstYield, which is assigned the returned value of gen.next() . When we call the next property of a generator object, we either start the execution context from the beginning, or go where we last left off. This is our first time calling it, so we start the execution context. We are now in line 2 inside the simpleGenerator function, which is where we come across yield 5 . The yield keyword is like the return keyword but instead of completely stopping the execution it will suspend the execution of the function. In this case it will return 5. Our firstYield variable is now assigned an object with the value property being 5. Line 9 — once again we have a const variable declaration named secondYield, which is assigned the returned value of gen.next() . This time the generator object remembers where its execution was last suspended and continues. We now are faced with a second yield statement. This time its yield 10 . Now the secondYield is assigned the returned object with the value property of 10.

Dynamic Generator Function

This is where the real power of generators will be seen. Once again I will walk through the code line by line.

Line 1 — we have a generator function declaration named dynamicGenerator. Line 8 — we have a const variable declaration named returnNextElement, which will be assigned the generator object that dynamicGenerator returns. Line 10 — we have a const variable declaration named element1, which is assigned the return value of returnNextElement.next() . This starts off the execution of the dynamicGenerator function. We are now in the execution of dynamicGenerator. First we have a const variable declaration named num, which is assigned the value 15. Then we are in line 3 — we have a const variable declaration named newNum, which is assigned…nothing yet. Before we can even assign it a value, the yield keyword throws us out while yielding the value of num. element1 finally gets value assigned to it. Which is an object with the value property being 15. element2 is declared and it is assigned the value of returnNextElement.next(2) . Unlike previous calls to the next function, this time we are passing 2 as an argument. What ever is passed to the .next function will replace the last previous yield statement. If we go back, the last yield statement was were num was yielded. The number 2 will replace the whole yield statement, and continue the execution. Last time, before we encountered the yield statement, we were about to assign newNum, because the number 2 replaces the yield statement that is assigned to newNum. Mind = blown! Lets continue to the next line — once again we encounter another yield statement. We are removed from the execution context and we are yielded the sum of 2 and newNum. element2 is finally assigned an object with the value property being 7.

Unto Async Await

Our journey has almost come to an end. Once again I will walk through the code, but keep it less verbose.

Line 1 — we created a generator function named createFlow. Line 8 — we created a function named handleFlow. Line 12 — we have a const variable named generatorObject, which is assigned the generator object that is returned by createFlow. Line 14 — we have a const variable declaration named returnedPromise(we will see why in a bit), it is assigned the returned value of our generatorObject.next() invocation. As we already know, calling the next property function will start a new local execution context. We are now inside the createFlow execution context. Line 2 — we have a const variable declaration named data, which is assigned..here we go again. We are using axios to make a simple http request to the star wars api. Axios returns a promise, and that promise is what gets yielded. Now returnedPromise is assigned an object with the yielded promise being the value property. Line 17 — we access the Promise we recently got and call the then function, we pass the handleFlow function to be called once the Promise is resolved. Finally, lets take a look at the handleFlow function; the function takes one argument which will be provided by the Promise once it’s resolved. Once we get the value from the promise, we call the generatorObject .next with the res.data as an argument. This will kick off the createFlow function again. As we saw before, the argument will replace the last yield statement. Now the data variable will be assigned the argument, which is the data returned by the api request. In line 4 we console.log the name property of the data, which is Luke Skywalker.

And that ladies and gentlemen is how we get the foundation of async await. Hopefully this tutorial was a helpful read.