What does async/await do and how should errors be handled with it?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
async functions implicitly return promises and let you await them with synchronous-looking code; await pauses the function without blocking the thread. Errors are handled with try/catch or .catch on the returned promise.
Detailed explanation
Marking a function async wraps its return value in a promise and allows await expressions inside. Await suspends the function's execution — other code keeps running — and resumes when the awaited promise settles. Rejections become thrown exceptions, so try/catch works naturally; alternatively attach .catch() to the call. Two subtleties trip people up: an async function *always* returns a promise even if you return a plain value, and awaiting inside loops serializes requests — Promise.all preserves concurrency for independent work. Sequential awaits are correct when each step needs the previous result. Since ES2022, top-level await works in modules. For multiple awaits where partial failures are acceptable, combine Promise.allSettled with await.
Example
async function loadDashboard() {
const user = await getUser(); // sequential: needs user
const [posts, notifications] = await Promise.all([
getPosts(user.id), // concurrent
getNotifications(user.id),
]);
return { user, posts, notifications };
}
loadDashboard()
.then(render)
.catch(err => console.error('Failed:', err));Interview tip
Volunteer the loop-vs-Promise.all distinction unprompted — accidental serialization is one of the most common real-world bugs and mentioning it lands strongly.
Common mistakes
- Awaiting inside forEach expecting parallelism (forEach ignores promises).
- Forgetting async functions always wrap returns in a promise.