The basic shape

async function load() {
  const res = await fetch("/api/data");
  const data = await res.json();
  return data;
}

Every async function returns a promise automatically, so callers can await it too.

Handle errors with try/catch

async function load() {
  try {
    const data = await fetchData();
    return data;
  } catch (err) {
    console.error("Failed:", err);
  }
}

A regular try/catch block catches a rejected promise, which is far easier to read than chained .catch() calls.

Run tasks in parallel with Promise.all

const [user, posts] = await Promise.all([
  fetchUser(),
  fetchPosts()
]);

Awaiting two calls one after another wastes time. Promise.all starts both at once and waits for both to finish.

Common mistakes

  • Using await outside an async function. It is a syntax error except at the top level of a module.
  • Awaiting in a loop when calls are independent. Use Promise.all to run them together.
  • Forgetting that an async function always returns a promise.

Frequently asked questions

What is the difference between async/await and promises?

They are the same mechanism. async/await is cleaner syntax built on top of promises, so you get the same behaviour with code that reads sequentially.

Can I await a non-promise value?

Yes. await on a plain value simply returns it, so it is safe to await something that may or may not be a promise.

Get comfortable with promises in our free JavaScript course.