Skip to main content

Command Palette

Search for a command to run...

Understanding Async/Await in JavaScript

Updated
•3 min read•View as Markdown

When working with asynchronous code in JavaScript, we learned about Promises.

Promises solved the problem of callback hell, but they still introduced another issue:

👉 too many .then() chains

As the logic grows, even promises can become hard to read.

This is why async/await was introduced.


Why Async/Await Was Introduced

Let’s look at a promise-based example:

getData()
  .then(data => processData(data))
  .then(result => saveData(result))
  .then(() => console.log("Done"))
  .catch(error => console.log(error))

This is better than callbacks, but:

  • still chain-heavy

  • not very natural to read

  • looks different from normal code

Async/await was introduced to make asynchronous code look like normal synchronous code.


Promise vs Async/Await

https://images.openai.com/static-rsc-4/5GDzGfR6PdbVtts10Ir07VsKlgCDQitfN1mfUGCPdYB3tRS79nOeg255cgljL6lidfH3Hg5o2HwlPTlkEaGRTsjWfSMcehEkpkRVToQR7V5tdyTjKKG6Ea2rvwcYUF8Q3pyB5QBeLojjwZnHOy0qhjDPKu6dpi_b3rifBv-wwoz8Ec2-EF0Ahh47vOfYixIg?purpose=fullsize

What is an Async Function?

An async function is a function that always returns a promise.

async function greet() {
  return "Hello"
}

greet().then(console.log)

Even though it returns a value, JavaScript wraps it inside a promise.


The Await Keyword Concept

The await keyword is used inside async functions.

It pauses the function until the promise is resolved.

Example:

async function getData() {
  let response = await fetch("https://api.example.com/data")
  let data = await response.json()

  console.log(data)
}

Here:

  • await waits for the result

  • code runs step by step

This makes it feel like normal code.


Error Handling with Async Code

With promises, we used .catch().

With async/await, we use try...catch.

async function getData() {
  try {
    let response = await fetch("https://api.example.com/data")
    let data = await response.json()
    console.log(data)
  } catch (error) {
    console.log("Error:", error)
  }
}

This looks like normal error handling and is easier to manage.


Comparison with Promises

Let’s compare both approaches.

Using Promises:

fetch("https://api.example.com/data")
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.log(error))

Using Async/Await:

async function fetchData() {
  try {
    let response = await fetch("https://api.example.com/data")
    let data = await response.json()
    console.log(data)
  } catch (error) {
    console.log(error)
  }
}

Async/await is:

  • cleaner

  • easier to read

  • easier to debug


What Actually Happens Behind the Scenes

Important point:

async/await does NOT replace promises

it is built on top of promises

So internally, it still uses promises — just hides complexity.


How to Think About It

Instead of chaining .then():

Think like this:

  • wait for result

  • then continue

It makes async code feel like normal step-by-step execution.


One Line Summary

Async/await = a cleaner way to write promise-based code


Conclusion

Async/await improves readability by making asynchronous code look like synchronous code.

It simplifies promise handling, improves error management, and makes code easier to understand.

Once you start using async/await, it becomes the preferred way to handle asynchronous operations in JavaScript.