Skip to main content

async/await, explained.

Published 2021/05/14 08:00

Introduction

So as we mentioned before, Promises are a way of telling Javascript, "go fetch some data but I'm not going to sit and wait because my browser would freeze. When you DO get a response eventually, do THIS with the data":

For example:

getData("http://api.example.com/data")
    .then((response) => {
        console.log(response)
    })

What the code basically does is:

  • request the data
  • when the data is received print them to the console

Now imagine this scenario:

  • You need to make an API call to get user details
  • You then need to extract the User ID from the details
  • Then you need to make another API call to get user records using the User ID you got from the first API call

To accomplish this, you will need to call a Promise within a Promise:

getData("http://api.example.com/get-user-details")
    .then((userDetails) => {
        getData("http://api.example.com/records/" + userDetails.id)
            .then((recordsById) => {
                console.log(recordsById)
            })
    })

You can see how this can become messy. What if you need to do 3 API calls? Or 4? Or more? It will become a nightmare to maintain! Take a look at this:

getData("http://api.example.com/get-user-details")
    .then((userDetails) => {
        getData("http://api.example.com/records/" + userDetails.id)
            .then((recordsById) => {
                post("http://api.example.com/save", {records: recordsById})
                    .then((response) => console.log(response))
        })
    })

🤷‍♂️ Is there a better way to do this? A cleaner, less messy way that doesn't involve nesting promises within promises within promises?

Yes there is. 👍

Enter: async and await!

async/await is a way to tell the browser, "please sit and wait for data to return before proceeding to the next line (like how other programming languages do it), BUT DO NOT WORRY! I will STILL return a Promise at the end of all this so you won't freeze!"

How do we use this?

Step 1. Tell the browser your function will be returning a Promise

First we want to make a commitment that this whole thing will return a Promise. This is what async does. It declares a function as "asynchronous", basically meaning that it will return a Promise.

This is how it's done:

async function stuffWithData(){

}

No matter what you return here, it will be returned as a Promise.

Step 2. Make your browser wait for responses

Now we can tell this function, "whenever you request data, sit and wait for a response before proceeding to the next line. And we do this with the await keyword.

Example:

async function stuffWithData(){
    console.log("Getting user details...")
    var userDetails = await getData("http://api.example.com/get-user-details")
    console.log("All done!")
    return userDetails
}

What the code above does:

  • It prints "Getting user details…" in the console
  • Requests some data and awaits for them to be returned
  • Saves the response in the userDetails variable
  • Once this is done, print "All done!" to the console.
  • Return the contents of userDetails

Hang on a minute…

"But", I hear you ask, "didn't we say that sitting and waiting for data to be received will freeze my browser? What's going on here?"

In this case, NO! Why? Because we used async at the beginning of our function, the function can only return a Promise at the end, which in this case contains the contents of userDetails as a response. That means your browser is safe from freezing! 🙌

With async/await, this is what your code now looks like:

async function stuffWithData(){
    var userDetails = await getData("http://api.example.com/get-user-details")
    var recordsById = await getData("http://api.example.com/records/" + userDetails.id)
    var response = await post("http://api.example.com/save", {records: recordsById})
    return response
}

Compare this with the previous code. Much less messy right?

Because this function returns a Promise, you'll need to call it the usual way to get the response:

stuffWithData()
    .then((response) => {
        console.log(response)
    })

And this is what makes async/await so great and so friendly to both the browser, the user and the developer!

Happy browser 💻

Happy user 💁‍♂️

Happy developer! 👨‍💻

Thank you for reading. I hope this made async/await a little clearer!

Dev, Explained (43 part series)

  1. Javascript Scopes, explained.
  2. Javascript Promises, explained.
  3. Accessibility, explained.
  4. React, explained
  5. Should I use forEach() or map()?
  6. Should I use Flexbox or CSS Grid?
  7. Docker, explained.
  8. Unit testing, explained
  9. Git, explained.
  10. Typescript, explained.
  11. async/await, explained.
  12. The DOM, explained.
  13. Regular expressions, explained
  14. GraphQL, explained.
  15. Vue, explained.
  16. Svelte, explained.
  17. API, explained.
  18. Javascript Hoisting, explained.
  19. Immediately Invoked Function Expressions (IIFE), explained.
  20. ARIA roles, explained.
  21. Test-driven Development, explained.
  22. ARIA live regions, explained.
  23. aria-label in accessibility, explained.
  24. Type coercion in Javascript, explained.
  25. Variables, explained.
  26. if statements, explained.
  27. Arrays, explained.
  28. Currying in Javascript, explained.
  29. Memoization, explained.
  30. For loops, explained.
  31. Javascript Prototypes, explained.
  32. React Hooks, explained.
  33. Graph databases, explained.
  34. MongoDB, explained.
  35. Serverless, explained.
  36. Javascript Callback functions, explained.
  37. HTML, explained.
  38. CSS, explained.
  39. Responsive design, explained.
  40. Javascript, explained.
  41. The CSS Box Model, explained.
  42. CSS Flexbox, explained.
  43. CSS Grid, explained.
2022 Savvas Stephanides
Buy me a coffee
Some icons from Freepik