ColorCode

Videos 🎥Courses 📚Podcast 🎙️Merch 👕Login 🏠
arrow left
20 Things JavaScript Developers Should Know

VIDEOS

Last Updated: February 4, 2023

Async Await

What is Async/Await and how do we use them with Promises?

A🚰A✋... in other words: Async Await

What is async/await? Why does it exist? What do we use it for? And when?

In this video about Asynchronous Programming I showed you what asynchronous programming is vs. synchronous, we used callbacks to achieve async, then in episode 12 we took that callback solution and converted it to Promises.

In this episode we’ll take the same example and convert it to use async/await, ALONGSIDE promises. If you haven’t seen those two episodes I suggest you do that first. Here they are. Then I’ll show you a couple more realistic and interesting examples and we’ll go from there.

If you remember from the Promise Video there are two parts to any promise. There’s the promise creator, and the promise receiver. In other words, you have one piece of code that creates a promise and returns it, like this function:

function getData() { return new Promise(function(resolve, reject) { resolve('some data'); }); }

then you have another piece of code that calls the function, takes the promise and handles it using a then block, something like this:

const promise = getData() promise.then(function(data) { const result = data })

We can actually get rid of the promise variable and write it like this

getData().then(function(data) { const result = data });

So take a look at that result variable. It’s inside a then block. That kind of annoys me. I don’t like that it’s inside a separate block. But we need to do that because this is async code.

But wouldn’t it be cool if we could write async code as if it was synchronous? Like regular serial code reading top to bottom, one line after another? Instead of nesting code inside code blocks?

Like something like this where we just create our result variable and assign it to the return value of the getData function:

const result = getData()

Well, no because getData doesn’t return the actual value, it returns the promise of a value. I explain why in full detail in this video. Or in 1 minute in this YouTube Short about Promises.

The bottom line is JavaScript thinks this is synchronous code and doesn’t wait for the function’s async operation. Unless...!

You put await in front of the function invocation.

const result = await getData();

Are you serious?? Let’s find out, CRAIG!

Let’s create a promise:

function getData() { return new Promise((resolve) => { setTimeout(() => { resolve(46) }) }) }

Let’s call it and see what we get

const result = getData() console.log(result) // Promise

Ok, it’s obviously just a Promise. Now let’s use await and call it:

const result = await getData() console.log(result) // SyntaxError

What? Error!

SyntaxError: await is only valid in async functions and the top level bodies of modules

So what’s happening here? The reason why it’s called async/await is because in order to use await you need to use async, in other words await can only be used inside functions that are async and since we’re not inside an async function we can’t use await. Actually we’re not in a function at all. So how do we make an async function? Simple, you create a function and put async in front of it:

async function start() { const result = await getData() console.log(result) // ? }

So now we actually have to call our function, which is annoying but stay with me for a second:

start() // 46

Ok so here’s the magic: I can call my getData function as if it was synchronous! It’s the difference between this:

const result = await getData()

and this:

getData().then(data => { const result = data })

So I can start using the result of my async operation as a regular variable, as opposed to some internal variable declared inside a then block. I like that.

Let’s simplify a bit. Let’s get rid of getData function, where we faked a timeout, let’s use a more realistic example. Let’s use the browser’s native fetch API to call an endpoint and get some data. We did this in the video about Promise too.

We know fetch returns a promise. So instead of creating this middleman function called getData let’s just call fetch.

async function start() { const data = await fetch('https://api.weather.gov/gridpoints/OKX/35,35/forecast'); const weather = await data.json() console.log(data.properties.periods[1].shortForecast) } start();

compared to:

function start2() { const result = await fetch('https://api.weather.gov/gridpoints/OKX/35,35/forecast') .then(data => result.json()) .the(data => data.properties.periods[1].shortForecast) }

A few important points:

1. Async and Await have to be used together

Like you saw we can only use await inside the body of an async function. Otherwise you get a syntax error:

####Two exceptions:

  1. await can be used on its own with JavaScript modules. I don’t wanna encourage or discourage it. There’s a link below, you can read more about it on MDN.
  2. Chrome DevTools allows you to use await, as of Chrome 62, so for a long time. So if you’re testing things out inside chrome devTools which I do all the time, and you don’t get a syntax error that’s why.

2. Async Await only affects the promise receiver

When using async/await you don’t change the promise creation. That stays the same. It only effects the promise usage side, meaning where you get returned a promise.

3. You can put await in front any function...

...that returns a promise. Like you saw we did it with getData but also with fetch.

4. Any function can become async

Can I put async in front of other function? Sure you can, Qoli!!!

Here’s an object method that returns a string. I can just change it to async and BOOM, it’s now async.

const me = { async sayHello() { return 'I am Qoli' // `I am Qoli` } } me.sayHello() // Promise { `I am Qoli` }

This means I can perform async operations inside the function and await the result. I don’t •have* to do anything async, but if I did I could write it with await, like this.

async function sayHello() { const status = await getMyStatus() return status }

You might have noticed the next point:

5. Async functions all return promises automatically

If you convert a function to async, it will make your function return a promise by default, even if you explicitly return something else. Check out the Qoli example above again ☝️

It sure looks like it returns a string but it doesn’t, it returns a promise, a resolved promise. Here’s an even simpler example:

async function myFun() { return 1 // gets converted to return Promise.resolve(1) }

6. Error handling with try/catch

One of the most important, yet neglected JavaScript skills is error handling.

In the Promises video I showed you how to handle errors with the catch block. We spent almost half of that video talking about error handling.

So if we don’t have the then block with async await then we probably don’t have the catch block either, right? Well, kind of...

You can use a catch block with await but you can also catch errors using a more old school method called try/catch. Here is how:

function getData() { return new Promise(function(resolve, reject) { setTimeout(() => { reject('Something went wrong!') }, 1) }) } async function start() { try { const result = await getData() } catch (error) { console.log(`Oops: ${error}`); } } start()

Now, with that said, you can still use a catch block:

async function start() { const result = await getData().catch(e => {console.log(e)}) console.log(result) }

The issue is your console.log will still run as if there was no error, this is a problem.

For one thing, we don’t want any of the success logic to run if the promise was rejected, so that’s potentially creating bugs.

But also we need to be able to separate the successful and failed scenarios in our code for readability and organization purposes.

And lastly, what’s the point of writing async await if you’re not going to take advantage of the synchronous looking nature of it? So that’s why it's pretty typical to use try/catch instead of a .catch block.

Now, are you gonna be able find some assh*le who can find a case against what I just said? Sure... But I don’t recommend it.

Ok, that about covers the basics of async await. Now go try it! Ok bye.