Async/Await in JavaScript Explained (With Real Examples)
Understand async/await in JavaScript: how it makes asynchronous code read like synchronous code, how it relates to promises, and how to handle errors properly.
- →async/await is syntax that lets you write promise-based asynchronous code as if it were synchronous.
- →An async function always returns a promise; await pauses inside it until a promise resolves.
- →Use try/catch to handle errors in async/await code.
- →await only works inside an async function (or at the top level of a module).
- →Run independent async tasks in parallel with Promise.all instead of awaiting them one by one.
Asynchronous JavaScript, fetching data, reading files, waiting for timers, used to mean nested callbacks or chained .then() calls. async/await makes it read like normal, top-to-bottom code. If promises confuse you, async/await is the friendlier face of the same thing.
What is async/await?
async/await is syntax built on promises. Mark a function async, and inside it you can await any promise, which pauses that function until the promise settles, then gives you the result, without blocking the rest of your program. The code reads sequentially even though it runs asynchronously.
async function getUser(id) {
const res = await fetch(`/api/users/${id}`);
const user = await res.json();
return user;
}Compare that to the promise version, same logic, more nesting:
function getUser(id) {
return fetch(`/api/users/${id}`)
.then((res) => res.json())
.then((user) => user);
}async functions always return a promise
Whatever you return from an async function is automatically wrapped in a promise. That's why you await it (or .then() it) from the outside. This is the key mental model: async/await doesn't remove promises, it's a cleaner way to write and consume them.
Handling errors with try/catch
A big win of async/await is normal error handling. Wrap awaits in try/catch just like synchronous code, no special .catch() chains.
async function getUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error("Request failed");
return await res.json();
} catch (err) {
console.error("Could not load user:", err);
return null;
}
}await only works inside an async function (or at the top level of an ES module). If you see 'await is only valid in async functions', you forgot to mark the enclosing function async.
Running tasks in parallel with Promise.all
A common mistake: awaiting independent tasks one after another, making them run in sequence when they could run at once. If tasks don't depend on each other, start them together with Promise.all.
// slow: runs one after another
const a = await getUser(1);
const b = await getUser(2);
// fast: runs both at once
const [a2, b2] = await Promise.all([getUser(1), getUser(2)]);Await in a loop when each step depends on the last. Use Promise.all when the steps are independent, it can be several times faster.
async/await vs promises: which to use?
They're the same underlying mechanism. Use async/await for readability, it's the default for most code today. Reach for raw promise methods like Promise.all, Promise.race and Promise.allSettled when you're coordinating multiple promises, they compose nicely with await.
The short version
async/await lets you write asynchronous, promise-based code as if it were synchronous. Mark the function async, await your promises, handle errors with try/catch, and use Promise.all to run independent tasks in parallel. It's the clearest way to work with asynchronous JavaScript.
Frequently asked questions
How do I use async/await in JavaScript?+
Mark a function with the async keyword, then use await before any promise inside it to pause until that promise resolves and get its result. For example, const res = await fetch(url); const data = await res.json(). Wrap awaits in try/catch to handle errors.
What's the difference between async/await and promises?+
async/await is syntax built on top of promises, it lets you write promise-based code that reads synchronously. An async function still returns a promise. Use async/await for readability, and raw promise methods like Promise.all when coordinating multiple promises.
How do I handle errors in async/await?+
Wrap your awaited code in a try/catch block, just like synchronous code. Any promise that rejects inside the try will jump to the catch, where you can log the error or return a fallback. You can also throw manually for failed responses.
Why does 'await is only valid in async functions' appear?+
await can only be used inside a function marked async, or at the top level of an ES module. If you see that error, add the async keyword to the enclosing function, or move the await into an async function.
How do I run multiple async tasks in parallel?+
Use Promise.all with an array of promises: const [a, b] = await Promise.all([taskA(), taskB()]). This starts all tasks at once and waits for them together, which is much faster than awaiting each one in sequence when the tasks are independent.
I build fast, SEO-ready sites and rank them on Google and AI search.