Skip to content

Async/Await

Async/await provides a more synchronous-looking syntax for working with Promises. Introduced in ES2017 (ES8), it makes asynchronous code look and behave more like synchronous code.

Promise chains could still become unwieldy:

function getUser() {
return fetch("/api/user")
.then(response => response.json())
.then(user => {
return fetch(`/api/posts/${user.id}`)
.then(response => response.json())
.then(posts => {
return { user, posts };
});
})
.catch(err => console.error(err));
}

Async/await makes it linear and readable:

async function getUser() {
try {
const response = await fetch("/api/user");
const user = await response.json();
const postsResponse = await fetch(`/api/posts/${user.id}`);
const posts = await postsResponse.json();
return { user, posts };
} catch (err) {
console.error(err);
}
}
// Arrow function version
const getUserData = async (id) => {
const response = await fetch(`/api/users/${id}`);
return await response.json();
};
// Top-level await (ES2022 - in modules)
const data = await fetch("/api/config").then(r => r.json());
// Parallel execution
async function getMultiple() {
// Sequential (slow)
const user = await fetchUser();
const posts = await fetchPosts();
// Parallel (fast)
const [user2, posts2] = await Promise.all([
fetchUser(),
fetchPosts()
]);
return { user2, posts2 };
}
  • Readable: Looks like synchronous code
  • Error handling: Use familiar try/catch
  • Debugging: Easier to set breakpoints and step through
  • Less nesting: Avoids callback/promise chain indentation
  • Intuitive: Easier for developers new to async programming
  • async functions always return a Promise
  • await can only be used inside async functions (except top-level in modules)
  • Forgetting await is a common mistake (you get a Promise instead of the value)
  • Sequential awaits can be slow; use Promise.all() for parallel operations
  • Error in await without try/catch creates unhandled promise rejection
  • await pauses function execution but doesnโ€™t block the event loop
// Common mistake: sequential when parallel would work
async function slow() {
const a = await fetch("/api/a"); // waits 1s
const b = await fetch("/api/b"); // waits 1s
// Total: 2s
}
async function fast() {
const [a, b] = await Promise.all([
fetch("/api/a"),
fetch("/api/b")
]);
// Total: 1s (parallel)
}
  1. Convert this to async/await: fetch('/api/user').then(r => r.json()).then(user => console.log(user))

    Answer
    async function getUser() {
    const response = await fetch('/api/user');
    const user = await response.json();
    console.log(user);
    }
  2. What does an async function return?

    Answer Always returns a Promise. If you return a value, it's wrapped in `Promise.resolve(value)`.
  3. How do you run three async operations in parallel and wait for all?

    Answer
    const [a, b, c] = await Promise.all([
    fetchA(),
    fetchB(),
    fetchC()
    ]);