JavaScript ES 2017: Learn Async/Await by Example
Async/Await explained through a clear example.
Udemy Black Friday Sale — Thousands of Web Development & Software Development courses are on sale for only $10 for a limited time! Full details and course recommendations can be found here.
Prerequisites
ES 2017 introduced Asynchronous functions. Async functions are essentially a cleaner way to work with asynchronous code in JavaScript. In order to understand exactly what these are, and how they work, we first need to understand Promises.
If you don’t know what Promises are, you should read this article I published on Promises before proceeding. You will not understand Async/Await in JavaScript until you understand Promises.
What is Async/Await?
- The newest way to write asynchronous code in JavaScript.
- It is non blocking (just like promises and callbacks).
- Async/Await was created to simplify the process of working with and writing chained promises.
- Async functions return a Promise. If the function throws an error, the Promise will be rejected. If the function returns a value, the Promise will be resolved.
Syntax
Writing an async function is quite simple. You just need to add the async
keyword prior to function
:
// Normal Functionfunction add(x,y){
return x + y;
}// Async Functionasync function add(x,y){
return x + y;
}
Await
Async functions can make use of the await
expression. This will pause the async
function and wait for the Promise to resolve prior to moving on.
Example Time
Enough talk. To understand what all of this means, lets look at an example! First we’re going to create some code using promises. Once we’ve got something working, we’ll rewrite our function using async/await so you can see just how much simpler it is!
If you’re using Google Chrome, be sure to follow along by typing in the code into your developer console. You can open the console by pressing Ctrl+Shift+J (Windows / Linux) or Cmd+Opt+J (Mac).
Consider the below code:
function doubleAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x * 2);
}, 2000);
});
}
In this code we have a function called doubleAfter2Seconds
. This function will take a number as input and will resolve two seconds later with the number doubled.
We can invoke our function and pass in the number 10 to try it out. To do this, we’ll call our function while passing in 10
. Then, after the promise has resolved, we’ll take our returned value and log it to the console. Here’s what this would look like:
doubleAfter2Seconds(10).then((r) => {
console.log(r);
});
Awesome!
But what if we want to run a few different values through our function and add the result? Unfortunately, we cant just add our invocations together and log them:
let sum = doubleAfter2Seconds(10)
+ doubleAfter2Seconds(20)
+ doubleAfter2Seconds(30);
console.log(sum);// undefined
The problem with the above code is it doesn’t actually wait for our promises to resolve before logging to the console.
One possible solution is to set up a promise chain. To do this we’ll create a new function called addPromise
. Our function will take an input value, and will return a Promise. Here’s what the boilerplate code looks like:
function addPromise(x){
return new Promise(resolve => { // Code goes here...
// resolve() });
}
Awesome. Now we can add in our calls to our doubleAfter2Seconds
function. Once we’re done, we can resolve with our new sum. In this example we should be returning x + 2*a + 2*b + 2*c
. Here’s the code:
function addPromise(x){
return new Promise(resolve => {
doubleAfter2Seconds(10).then((a) => {
doubleAfter2Seconds(20).then((b) => {
doubleAfter2Seconds(30).then((c) => {
resolve(x + a + b + c);
})
})
})
});
}
Lets walk through the code again, line by line.
- First, we create our function
addPromise
. This function accepts one parameter. - Next, we create our
new Promise
that we’ll be returning. Note that for the sake of simplicity, we’re not handling rejections/errors. - Next we invoke
doubleAfter2Seconds
for the first time, passing in a value of10
. Two seconds later, the return value of20
will be returned to thea
variable. - We invoke
doubleAfter2Seconds
again, this time passing in a value of20
. Two seconds later, the return value of40
will be returned to theb
variable. - We invoke
doubleAfter2Seconds
one final time, this time passing in a value of30
. Two seconds later, the return value of60
will be returned to thec
variable. - Finally, we resolve our Promise with the value of
10 + 20 + 40 + 60
or130
.
When we put all of the code together, here’s what it looks like:
Switching from Promises to Async/Await.
Awesome! Now lets see just how much easier we could write the above code with Async/Await!
Remove the addPromise
function, and create a new function named addAsync
. This function will have the exact same purpose as our addPromise
did. When you create your addPromise
function, make use of the async
keyword. Here’s what that looks like:
async function addAsync(x) { // code here...}
Now that you’ve created an async function, we can make use of the await
keyword which will pause our code until the Promise has resolved. Here’s how easy that is:
async function addAsync(x) {
const a = await doubleAfter2Seconds(10);
const b = await doubleAfter2Seconds(20);
const c = await doubleAfter2Seconds(30);
return x + a + b + c;
}
And here’s the full code:
As you can see, we’re still making use of the same doubleAfter2Seconds
function. Similarly, we’ll be invoking our addAsync()
function and passing in the value of 10
. Upon completion, we log the resulting value. Let’s walk through this step-by-step:
- First we call
addAsync(10)
passing in the value of10
. - Next, we get the value of
a
on line 10. Since theawait
keyword is used, our function pauses for two seconds while we wait for the promise to resolve. Once the promise resolves,a = 20
.
const a = await doubleAfter2Seconds(10);
- Next, we get the value of
b
on line 11. Since theawait
keyword is used, our function pauses for two seconds while we wait for the promise to resolve. Once the promise resolves,b = 40
.
const b = await doubleAfter2Seconds(20);
- Next, we get the value of
c
on line 12. Since theawait
keyword is used, our function pauses for two seconds while we wait for the promise to resolve. Once the promise resolves,c = 60
.
const c = await doubleAfter2Seconds(30);
- Finally, we can return the value of
x + a + b + c
. Since we passed in10
as our single parameter, we are returning the value of10 + 20 + 40 + 60
. - A full six seconds later, our
console.log(sum)
is finally run. The value of10 + 20 + 40 + 60
is passed in, and130
is logged to the console.
And that’s it! You’ve just created an asynchronous function in JavaScript!
As you can see, since Async functions return a Promise, they can be used interchangeably with Promises very easily. Our code is also so much cleaner and easier to read when we use Async/Await instead of long Promise chain.
Closing Notes:
Thanks for reading, and hopefully this was helpful. There is much more to Async/Await — including error handling — that we didn’t cover in this article.
If you’re still having trouble understanding what Async/Await is, it’s probably because you don’t fully understand how Promises work. Promises are key to understanding this topic. Additional information can be found on Promises here, here, and here.
If you’re ready to finally learn Web Development, check out The Ultimate Guide to Learning Full Stack Web Development in 6 months.
I publish 4 articles on web development each week. Please consider entering your email here if you’d like to be added to my once-weekly email list, or follow me on Twitter.