DEV Community

Cover image for Understanding Async & Await
Maxim Orlov
Maxim Orlov

Posted on • Updated on • Originally published at maximorlov.com

Understanding Async & Await

This article was originally published at https://maximorlov.com/understanding-async-await/

Learning async/await can be daunting. It's something you've been procrastinating on for weeks, if not months!

Anime terminator (learning async/await) haunting girl hiding under a desk (you).

You might know the difference between synchronous and asynchronous code, but you're completely lost in the application of it.

At this rate, it's hard to imagine how you'll ever wrap your head around asynchronous JavaScript. 😫

But learning async/await doesn't have to be scary!

With a little guidance and the right approach, you can write modern asynchronous code that just works. Not next month, or next week, but today.

It's true, async/await is unintuitive at first.. but only because you haven't built a mental model for it, yet!

To understand async/await we have to talk a little bit about promises first. Since async/await is built on top of promises, when you're writing async/await you're in fact dealing with promises under the hood.

What's a Promise?

Put simply, a Promise is a JavaScript object that represents a future value. It holds two pieces of information: the promise state, and a value or error (depending on the state).

A promise can be in one of these states:

  • pending — initial state, the operation is in progress
  • fulfilled — the operation completed successfully
  • rejected — the operation failed

A promise is settled when the promise has either fulfilled or rejected, but not pending. A promise eventually fulfills with a value or rejects with an error (or reason).

new Promise(executor) with state: "pending" on the left. Two arrows pointing to the right. One with resolve("ok") leading to state: "fulfilled" and value: "ok". Another with reject(error) leading to state: "rejected" and reason: error. Both fulfilled and rejected states are considered settled states.

A function that returns a promise is by definition an asynchronous function. (remember this, we'll come back to it later)

Even though the promise is returned synchronously, the value inside the promise is asynchronous and can only be accessed after the promise has fulfilled.

What does await actually do?

When you add the await keyword in front of a promise you instruct the JavaScript runtime to pause execution inside the current function, wait until the promise settles, and only after the promise has settled, continue executing the rest of the code inside that function.

Await guarantees that you have access to an asynchronous value past a certain point. The runtime won't execute any further code inside the function until the promise fulfills with the value (or rejects with an error).

One thing to keep in mind is that starting an asynchronous operation and awaiting its result are two separate actions. This becomes clear when you write them on different lines.

Therefore, await is solely responsible for pausing further execution until the asynchronous operation has completed. It is not what starts the asynchronous operation.

How about async?

The async keyword grants a special ability to a function.

A function marked as async can pause execution anywhere inside its body. In other words, the function is allowed to use the await keyword. Await can only be used inside async functions. (you'll understand why in a bit)

An async function has two important properties:

  1. It always returns a Promise
  2. You can use the await keyword inside its scope

When you return a non-Promise value inside an async function, the value is wrapped inside a Promise before being returned.

async function getFive() {
  return 5;
}

console.log(getFive()); // Promise { ... }
Enter fullscreen mode Exit fullscreen mode

Remember what I said earlier about functions that return a promise — they're by definition asynchronous. Therefore, a function marked as async is always asynchronous.

A non-async function that returns a promise is also asynchronous. The following code is practically the same as the one above:

function getFive() {
  return Promise.resolve(5);
}

console.log(getFive()); // Promise { ... }
Enter fullscreen mode Exit fullscreen mode

All other functions are considered synchronous functions.

Decision tree to determine whether a function is synchronous or asynchronous.

Why async & await are inseparable

Knowing that await pauses execution inside a function and that a non-async function is synchronous if it doesn't return a promise, you can start to see why the following code doesn't work:

function getFive() { // function is not async
  const five = await fetchFive(); // 🚫 doesn't work, can't use await
  return five;
}
Enter fullscreen mode Exit fullscreen mode

How can getFive() synchronously return five if it needs to wait for fetchFive() first?

Put differently, how can you wait for an asynchronous value and then proceed to return it synchronously?

You simply can't.

That's why await can only be used inside a function declared with the async keyword. An async function wraps the return value in a promise which makes the value asynchronous.

Hopefully you have a better understanding of async/await by now. Go ahead and use it in your projects!

Master Asynchronous JavaScript 🚀

Learn how to write modern and easy-to-read asynchronous code with a FREE 5-day email course.

Through visual graphics you will learn how to decompose async code into individual parts and put them back together using a modern async/await approach. Moreover, with 30+ real-world exercises you'll transform knowledge into a practical skill that will make you a better developer.

Refactoring Callbacks, a FREE 5-day email course. 30+ real-world exercises, a visual guide and 5 days, 5 lessons.

👉 Get Lesson 1 now

Top comments (16)

Collapse
 
timdenison profile image
Tim Denison

As a younger dev I read a lot of similar descriptions of async/await mechanics but didn’t fully understand, and it was never fully explained, what the value was. Why do I care? What does using this pattern give me, and how does THAT work?

You hint at the value by mentioning that await pauses execution of that particular function, which implies that the thread could go an execute other instructions during that time that the first function execution is paused, but as a younger dev I couldn’t intuit that implication. I wished I had someone offering a mental model for that aspect of asynchronous programming when I was younger.

Collapse
 
brense profile image
Rense Bakker

Very nice detailed explanation of asynchronous JavaScript!

Collapse
 
maximization profile image
Maxim Orlov

Thank you Rense!

Collapse
 
eshimischi profile image
eshimischi

Async/await is just a syntax sugar for Promise/then.

Collapse
 
srnascimento40 profile image
SrNascimento40

Your article clarifies that concept for me, thanks for sharing it with us!

Collapse
 
maximization profile image
Maxim Orlov

Happy to hear it clarified this topic for you!

Collapse
 
azimsabbir profile image
Mohammad Azim Sabbir

thank you very much that was helpful

Collapse
 
maximization profile image
Maxim Orlov

Glad to hear you found it helpful!

Collapse
 
alvesjessica profile image
Jessica Alves

Nice explanation 👏

Collapse
 
maximization profile image
Maxim Orlov

Thanks Jessica!

Collapse
 
cmcoder2012 profile image
CM

The simple explanation from a master of JS guru.

Collapse
 
maximization profile image
Maxim Orlov

That's flattering, thanks 😊. Glad you liked it!

Collapse
 
azzarox profile image
Azzarox

Do I need to always use await when calling the function (to retrieve the value) or I can omit using await if I don't need to use the retrieved value. For example if I have 'guests' in my database and I have function like find() which returns all of my guests (which is promise). Do I need to use await in some other function if I just want to call the function (that retrieves the guests) but I don't need to use the value. I think I know the answer already due to the article but still would like to ask. Great article regardless, one of the best I have read on the subject.

Collapse
 
maximization profile image
Maxim Orlov

Great question! If you're not using the value you don't have to use await. But beware, if the functions throws the error won't be caught in the catch-block. Also any code running after the async function cannot assume the function has completed successfully. Say you run sendNotification() in the backend and then respond to the client that the notification has been sent, well, you don't know that for sure :). Hope that makes sense!

Collapse
 
azzarox profile image
Azzarox

Yes, absolutely! Thank you very much.

Collapse
 
crazyrunsnail profile image
davino

what software you used to draw