LearnFrenzy
Sign in Take a free test

Asynchronous JavaScript · Lesson 26 of 40

async and await in JavaScript

5 min read Updated Nov 7, 2026 Saurabh Samir

async/await (ES2017) is syntax on top of promises that lets you write asynchronous code top to bottom, like synchronous code, with ordinary try/catch for errors. It's how almost all modern JavaScript – React data loading, Node.js APIs, test suites – handles async work.

In this lesson

  • How async functions and await work
  • Error handling with try/catch/finally
  • Sequential vs parallel – the biggest performance mistake
  • Loops, retries and top-level await

The basics

const wait = (ms, value) => new Promise((r) => setTimeout(() => r(value), ms));
const getUser = (id) => wait(30, { id, name: "Asha" });
const getOrders = (userId) => wait(30, [{ id: 101, total: 1200 }, { id: 102, total: 450 }]);

async function showSpend(userId) {
  const user = await getUser(userId);          // pause here until it resolves
  const orders = await getOrders(user.id);
  const total = orders.reduce((sum, o) => sum + o.total, 0);
  return `${user.name} spent ₹${total}`;       // an async function returns a promise
}

const p = showSpend(7);
console.log(p instanceof Promise);
console.log(await p);

Output

true
Asha spent ₹1650
  • async before a function makes it always return a promise: a returned value becomes a fulfilled promise; a thrown error becomes a rejected one.
  • await pauses this function (not the whole program) until the promise settles, then gives you its value – or throws its error.
  • In ES modules you can use await at the top level, as the last line above does.

Error handling

const fakeApi = (path) => new Promise((resolve, reject) =>
  setTimeout(() => path === "/profile"
    ? resolve({ name: "Ravi" })
    : reject(new Error(`404 Not Found: ${path}`)), 20));

async function loadPage(path) {
  console.log("Loading", path);
  try {
    const data = await fakeApi(path);
    console.log("Loaded:", data.name);
  } catch (err) {
    console.log("Error:", err.message);      // rejected await lands here
  } finally {
    console.log("Hide spinner");             // runs either way
  }
}
await loadPage("/profile");
await loadPage("/settings");

Output

Loading /profile
Loaded: Ravi
Hide spinner
Loading /settings
Error: 404 Not Found: /settings
Hide spinner

Sequential vs parallel

Each await waits for the previous one. If the operations don't depend on each other, start them all first and await them together:

const wait = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
const getProfile = () => wait(100, "profile");
const getCourses = () => wait(100, "courses");
const getBadges = () => wait(100, "badges");

let t = Date.now();
const a = await getProfile();
const b = await getCourses();
const c = await getBadges();
const sequential = Date.now() - t;

t = Date.now();
const [x, y, z] = await Promise.all([getProfile(), getCourses(), getBadges()]);
const parallel = Date.now() - t;

console.log(sequential >= 300 ? "sequential: ~300 ms" : sequential);
console.log(parallel < 200 ? "parallel: ~100 ms" : parallel);

Output

sequential: ~300 ms
parallel: ~100 ms

Choosing

  1. Does step 2 need step 1's result?yes → await one after the other
  2. Independent requests?start all, then await Promise.all
  3. Some may fail but you want the rest?await Promise.allSettled

await in loops

const wait = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
const ids = [3, 1, 2];

// for...of with await: one at a time, in order
for (const id of ids) {
  console.log("sequential", await wait(id * 10, id));
}

// map + Promise.all: all at once, results still in input order
const results = await Promise.all(ids.map((id) => wait(id * 10, `item ${id}`)));
console.log(results);

// forEach does NOT wait for async callbacks
ids.forEach(async (id) => { await wait(5); });
console.log("forEach returned immediately");

Output

sequential 3
sequential 1
sequential 2
[ 'item 3', 'item 1', 'item 2' ]
forEach returned immediately

Common mistakes

  • Using forEach with an async callback and expecting it to wait – use for...of or Promise.all.
  • Forgetting await: const user = getUser() gives you a pending promise, not the user.
  • Calling an async function without handling its rejection – wrap in try/catch or add .catch.

Retry with backoff

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
let calls = 0;
async function flakyRequest() {
  calls++;
  if (calls < 3) throw new Error(`Attempt ${calls} failed`);
  return "Data received";
}

async function retry(fn, attempts = 4, delay = 20) {
  for (let i = 1; i <= attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      console.log(err.message);
      if (i === attempts) throw err;
      await sleep(delay * 2 ** (i - 1));     // 20, 40, 80 ms…
    }
  }
}
console.log(await retry(flakyRequest));

Output

Attempt 1 failed
Attempt 2 failed
Data received

Note return await fn() inside try: without await, a rejection would escape the try block and skip the retry.

Practice

Try it yourself

  1. Load three "pages" in parallel with Promise.allSettled and print how many succeeded.

    Show solution
    const load = (ok, v) => new Promise((res, rej) => setTimeout(() => (ok ? res(v) : rej(new Error(v))), 10));
    const results = await Promise.allSettled([load(true, "home"), load(false, "admin"), load(true, "blog")]);
    const ok = results.filter((r) => r.status === "fulfilled").map((r) => r.value);
    console.log(`${ok.length} of ${results.length} loaded:`, ok.join(", "));

    Output

    2 of 3 loaded: home, blog

Quick check

What does an async function return?

Always a promise.

Does await block the whole program?

No – it pauses only the async function; other code and events keep running.

How do you run three independent requests at once?

await Promise.all([a(), b(), c()]) – start them together, then await.

Summary

  • async functions return promises; await unwraps them and throws on rejection.
  • Use try/catch/finally for errors; await independent work in parallel with Promise.all.
  • for...of awaits in order; forEach doesn't wait; use return await inside try.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Popular