Skip to content

Promises, Async, and Await

Mastering asynchronous JavaScript can be tricky. This guide walks you through the problems callbacks introduce, how Promises help, and why async/await makes your code cleaner and more readable.


🤔 What Is async in JavaScript?

Problem: You want a function that always returns a Promise.

Solution: Prefix it with async.

  • An async function always returns a Promise.
  • If you return a non-Promise value, JavaScript wraps it in a resolved Promise.
async function getData() {
  return "Hello World";  // Returns Promise.resolve("Hello World")
}

const dataPromise = getData();
console.log(dataPromise); // Promise {<fulfilled>: "Hello World"}
dataPromise.then(res => console.log(res)); // Hello World

If you return a Promise explicitly, it stays as is:

const p = new Promise(resolve => setTimeout(() => resolve("Delayed"), 2000));

async function getData() {
  return p; // returns p unwrapped
}

getData().then(console.log); // after 2s logs "Delayed"

Handling Promises: .then() vs await

1. Using .then() (Old Way)

Using .then()
1
2
3
4
5
6
7
8
const p = new Promise(resolve => setTimeout(() => resolve("Hello"), 2000));

function getData() {
  p.then(res => console.log(res));
  console.log("Runs before promise resolves");
}

getData();
Console Output
Runs before promise resolves
Hello

2. Using async/await

Using async/await
1
2
3
4
5
6
7
8
async function getData() {
  console.log("Waiting for promise...");
  const res = await p;          // pauses here
  console.log(res);
  console.log("After await");
}

getData();
Console Output
Waiting for promise...
Hello
After await

Behind the Scenes of await

When you await a Promise:

  1. The async function is suspended at that point.
  2. It’s removed from the call stack (the main thread is free).
  3. When the Promise resolves, the function resumes where it left off.

This prevents blocking the UI and keeps your app responsive.


🌐 Real-World Example: fetch

Problem: You need to fetch JSON data from an API.

const API_URL = "https://api.github.com/users/yourusername";

async function fetchUser() {
  try {
    const response  = await fetch(API_URL);      // 1. fetch() returns a Promise
    const jsonValue = await response.json();      // 2. response.json() returns a Promise
    console.log(jsonValue);
  } catch (err) {
    console.error("Error fetching user:", err);
  }
}

fetchUser();

Key Points:

  • Both fetch() and response.json() return Promises.
  • await pauses only the async function, not the entire JavaScript engine.
  • Use try/catch to handle network or parsing errors.

⚠ Error Handling

1. try…catch inside an async function

async function safeFetch(url) {
  try {
    const res  = await fetch(url);
    const data = await res.json();
    return data;
  } catch (err) {
    console.error("Fetch error:", err);
  }
}

2. .catch() on the returned Promise

async function badFetch() {
  const res = await fetch("https://invalid.url");
  return res.json();
}

badFetch().catch(err => console.error("Caught:", err));

📢 Quick Interview Tips

What is async?

Marks a function to always return a Promise.

What is await?

Pauses an async function until a Promise settles.

Why use async/await?

Cleaner syntax, easier error handling.

When not to use it?

For small one-off Promises or in environments without ES2017 support.


🗒 async/await vs .then()/.catch()

  • Syntax & Readability

    • .then(): chaining callbacks, can become nested
    • async/await: flat, “top-to-bottom” flow
  • Error Handling

    • .catch(): single or per-chain handlers
    • try…catch: group multiple awaits or isolate individual calls
  • Sequential vs. Parallel

    • Sequential by default in both (await a; await b;)
    • Parallel with Promise.all([…, …])
  • Debugging & Stack Traces

    • .then(): anonymous callbacks in traces
    • async/await: resembles sync code, easier breakpoints
  • When to Use

    • async/await: multiple dependent steps, cleaner logic, modern codebases
    • .then()/.catch(): simple one-off Promises, existing promise-only libraries

Both patterns run on Promises; choose based on readability, error-handling style, and project needs. async/await is purely syntactic sugar.