Skip to main content

Command Palette

Search for a command to run...

Async/Await in JavaScript

Learn to Write Cleaner Asynchronous Code.

Published
3 min read
Async/Await in JavaScript

You've met promises. You understand .then(). You've chained a few calls together and it mostly worked. But then you needed to do three async things in sequence, and you ended up with something like this:

getUser(userId)
  .then(user => {
    return getOrders(user.id);
  })
  .then(orders => {
    return getProduct(orders[0].productId);
  })
  .then(product => {
    console.log(product.name);
  })
  .catch(err => {
    console.error(err);
  });

It works. But it reads sideways. Each .then() is a new indentation, a new callback, a new mental context to hold. You can't easily share variables between steps without hoisting them outside the chain. Error handling applies to the whole chain but it's tacked on at the end, invisible until something breaks.

async/await was introduced in ES2017 to fix exactly this. Not by replacing promises by giving you a way to write promise-based code that looks and reads like regular synchronous code.

Syntactic sugar over promises

The first thing to understand is that async/await is not a new async system. It's a new syntax for working with promises. Under the hood, every async function returns a promise. Every await pauses execution and waits for a promise to resolve. No new engine magic just a cleaner way to write what you were already doing.

Think of it this way. Promises gave you a contract: "this will eventually have a value." async/await gives you a way to write code as if that value is already there, and JavaScript handles the waiting behind the scenes.

The async keyword

Putting async before a function declaration does one thing: it makes that function always return a promise. Even if you return a plain value, JavaScript automatically wraps it in a resolved promise.

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

greet().then(msg => console.log(msg)); // "Hello!"

You returned a string. But because the function is async, the caller receives a promise that resolves to that string. That's the contract.

You can use async with any function style:

// function declaration
async function fetchData() { ... }

// arrow function
const fetchData = async () => { ... }

// method in an object
const api = {
  async getUser() { ... }
};

The await keyword

await can only live inside an async function. It pauses that function's execution until the promise it's waiting on resolves then hands you the resolved value directly.

async function loadUser() {
  const user = await getUser(1); // pauses here until resolved
  console.log(user.name);        // then continues
}

Without await, getUser(1) returns a promise object not the user. With await, you get the user directly, as if the function was synchronous. The pause is real but it's non-blocking: while this function is waiting, JavaScript keeps running everything else.

Here's what that promise chain from earlier looks like rewritten with async/await:

async function loadProductFromUser(userId) {
  const user    = await getUser(userId);
  const orders  = await getOrders(user.id);
  const product = await getProduct(orders[0].productId);

  console.log(product.name);
}

Top to bottom. Left to right. Each line waits for the previous one before moving on. No callbacks. No indentation staircase. It reads like a recipe: get the user, get their orders, get the first product, show its name.

Here's the execution flow when you call an async function:

JavaScript

Part 3 of 24

Master JavaScript from the ground up with a structured, easy-to-follow learning path designed for serious developers. This series starts with core fundamentals like variables, data types, and control flow, then gradually moves into deeper topics such as functions, scope, prototypes, asynchronous programming, and how the JavaScript engine works internally. Each lesson focuses on clarity and real understanding. You will learn not only how to write JavaScript, but why it behaves the way it does. Concepts are explained using simple examples, practical use cases, and clean coding patterns that reflect real-world development.

Up next

JavaScript Promises Explained for Beginners

JS Promises for Beginners