How JavaScript Async/Await Works Under the Hood

For JavaScript Web Developers

Thon Ly
Silicon Wat University
3 min readSep 30, 2017

--

Photo: https://commons.wikimedia.org/wiki/File:JavaScript-logo.png

When you use my referral link above 👆 to become a Medium member, all proceeds will be donated towards the construction of the Silicon Wat Campus for children in Ukraine and Cambodia ❤️

Introduction

The web is asynchronous in nature. User interfaces wait for user inputs. Servers wait for network requests. Databases wait for queries and mutations. The JavaScript language understands this, providing Promises in the ES6 specification to simplify asynchronous programming. Even more exciting is Async/Await coming to ES8 that further streamlines the behavior of using Promises.

For example, the Fetch API provides an interface for making network requests, returning Promises for us to resolve. To use it to get the current weather in Long Beach, we chain together two then callbacks:

In the first, we create a callback function to receive the Response object and return back its JSON data. In the second, we create a callback that receives that data and then logs it to the console.

Using Async/Await, the same code becomes:

By wrapping the logic inside an async function, we can replace the then callbacks with await statements. The effect, the code pauses execution on those lines until the Promises resolve! Asynchronous programming becomes synchronous! 😲

Believe it or not, Async/Await is just syntactic sugar. In this article, we will examine how it all works under the hood. To do that, we will attempt to recreate the async function from scratch!

If you’re looking for A Complete Frontend Developer Course for Beginners, check out this textbook written by Thon Ly exclusively for Medium:

To help you achieve full mastery, all three web languages (HTML, CSS, and JavaScript) are taught together in parallel within a musical context in order to deepen your understanding of their interrelationships in a fun and memorable way!

Async Function

The key insight is to use Generators. Ultimately, we want to create an async function that takes in a generator. That way, we can nest yield statements that look like this:

Doesn’t this look uncannily like the await statements in getWeather()? In fact, await statements are just yield statements under the hood!

Thus, we need our async “polyfill” to instantiate the generator, recursively nesting next for each yield statement inside its Promise’s then callback until done is true. In other words, when each Promise resolves, its value will be passed as an argument to next, whereby g.next will replace its corresponding yield statement with that value.

In effect, we can assign the value of any Promise to any variable inside the generator!

Clever, right? 😉

Example in live code:

Reference: Async/Await Specification

When you use my referral link above 👆 to become a Medium member, all proceeds will be donated towards the construction of the Silicon Wat Campus for children in Ukraine and Cambodia ❤️

Conclusion

Async/Await enables us to write asynchronous code in a synchronous fashion, which produces cleaner and easier-to-understand logic. Under the hood, it’s just syntactic sugar using generators and yield statements to “pause” execution. In other words, async functions can “pull out” the value of a Promise even though it’s nested inside a callback function, giving us the ability to assign it to a variable!

In fact, generators and even Promises themselves are also “syntactic sugars”! — clever designs to help us avoid writing callback hell. We hope this article gave you a better intuition behind this awesome feature coming to ES8. 😇

--

--