How JavaScript Async/Await Works Under the Hood
For JavaScript Web Developers
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. 😇