Skip to main content

Command Palette

Search for a command to run...

Async/Await in JavaScript: Writing Cleaner Asynchronous Code

Published
3 min read
Async/Await in JavaScript: Writing Cleaner Asynchronous Code

In this article we'll understand the async-await keyword of JavaScript. Before understanding what something is, it is always a good idea to know why it exist at all. So to answer that question look at this code which isn't using async-await keyword:

function fetchUser() {
  fetch("https://api.example.com/user")
    .then(response => response.json())
    .then(data => {
      console.log("User:", data);
      return fetch(`https://api.example.com/posts/${data.id}`);
    })
    .then(response => response.json())
    .then(posts => {
      console.log("Posts:", posts);
    })
    .catch(err => {
      console.log("Error:", err);
    });
}

At first glance, this might look fine. But as the logic grows:

  • Multiple .then() chains make it harder to follow

  • Error handling becomes less intuitive

  • Code readability decreases

This is exactly why async/await was introduced


Why Async/Await Was Introduced

Async/await is syntactic sugar over Promises.

It doesn’t replace Promises — it simply provides a cleaner and more readable way to write asynchronous code.

Problems it solves:

  • Deep .then() chaining

  • Callback-like nesting

  • Difficult debugging in complex flows


How Async Functions Work

An async function always returns a Promise.

async function greet() {
  return "Hello";
}

This is equivalent to:

function greet() {
  return Promise.resolve("Hello");
}

Even if you return a normal value, JavaScript wraps it inside a Promise.


Await Keyword Concept

The await keyword can only be used inside an async function.

It pauses execution until a Promise is resolved.

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

  console.log("User:", data);

  let postResponse = await     fetch(`https://api.example.com/posts/${data.id}`);
  let posts = await postResponse.json();

  console.log("Posts:", posts);
}

What changed?

  • No .then() chaining

  • Step-by-step execution

  • Much easier to read and understand

It looks like synchronous code, but it’s still asynchronous under the hood.


Error Handling with Async Code

Instead of .catch(), async/await uses try...catch.

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

    let postResponse = await fetch(`https://api.example.com/posts/${data.id}`);
    let posts = await postResponse.json();

    console.log(posts);
  } catch (error) {
    console.log("Error:", error.message);
  }
}

Why this is better:

  • Cleaner structure

  • Centralized error handling

  • Similar to synchronous programming


Comparison with Promises

Using Promises:

fetch("https://api.example.com/data")
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.log(err));

Using Async/Await:

async function getData() {
  try {
    let res = await fetch("https://api.example.com/data");
    let data = await res.json();
    console.log(data);
  } catch (err) {
    console.log(err);
  }
}

Key Differences:

Feature Promises Async/Await
Syntax .then() chains Clean & linear
Readability Medium High
Error Handling .catch() try...catch

Why Async/Await Improves Readability

  • Code flows top-to-bottom

  • Less nesting

  • Easier to debug

  • More intuitive for beginners

You write async code the same way you think about it.


Final Thoughts

Async/await is one of the most important features in modern JavaScript.

  • It is built on top of Promises

  • Makes asynchronous code cleaner

  • Reduces complexity in real-world applications


Quick Summary

  • async → makes a function return a Promise

  • await → pauses execution until Promise resolves

  • Works only inside async functions

  • Uses try...catch for error handling

  • Improves readability significantly


Once you start using async/await, going back to .then() chains will feel unnecessarily complicated

.