Technology · JavaScript
JavaScript Async and Await
Handle async code cleanly with async functions, await, error handling, and parallel execution.
TL;DR
- 01Mark functions async to make them return promises.
- 02Use await to pause and unwrap promise values.
- 03Wrap awaited code in try-catch for error handling.
Async Functions
- Mark a function
asyncto make it always return a promise.async function fetchData() { return "data"; } fetchData().then(result => console.log(result)); - An async function that returns a value wraps it in a resolved promise.
- You can use
awaitonly inside async functions.async function getData() { const response = await fetch("/api/data"); return response.json(); } - Async functions are just a cleaner way to work with promises.
- Every async function returns a promise, even if it doesn't use await.
Await Keyword
- Use
awaitto pause execution until a promise resolves.async function getUser(id) { const response = await fetch(`/api/users/${id}`); const user = await response.json(); return user; } - Await unwraps the resolved value from a promise automatically.
- Await can only be used inside async functions or at module top level.
- Each await pauses the function until that promise settles.
async function getMultiple() { const a = await fetch("/a"); // waits const b = await fetch("/b"); // waits for /a first return [a, b]; } - Do not use await for independent operations — use Promise.all instead.
Error Handling
- Wrap await calls in
try-catchto handle rejection errors.async function fetchData() { try { const res = await fetch("/data"); return await res.json(); } catch (error) { console.error("Failed to fetch:", error); return null; } } - Catch blocks run when any await in the try block rejects.
- Use
finallyto run cleanup code regardless of success or failure.async function withCleanup() { try { return await operation(); } finally { cleanup(); } } - Throw errors from async functions to propagate them as promise rejections.
- Attach
.catch()to an async call when you prefer promise chaining.fetchData() .then(data => process(data)) .catch(error => console.error('Failed:', error.message));
Parallel Execution
- Use
Promise.all()to await multiple independent operations in parallel.async function getUsers() { const [user1, user2] = await Promise.all([ fetch("/users/1").then(r => r.json()), fetch("/users/2").then(r => r.json()) ]); return [user1, user2]; } - This is much faster than awaiting sequentially.
- Use
Promise.race()to get the first result from multiple promises.const fastest = await Promise.race([api1(), api2()]); - Use
Promise.allSettled()when you want all results, even if some fail. - Use
Promise.any()to resolve as soon as the first promise succeeds.const result = await Promise.any([ fetch('/endpoint-1').then(r => r.json()), fetch('/endpoint-2').then(r => r.json()) ]); // Resolves with whichever responds first without rejecting
Common Patterns
- Top-level await in modern JavaScript (ES2022+) for script initialization.
// In a module const config = await loadConfig(); - Chain multiple async operations with proper error handling.
async function workflow() { const data = await fetch1(); const result = await process(data); return await fetch2(result); } - Use async IIFE for immediate async execution without named functions.
(async () => { const data = await fetchData(); console.log(data); })(); - Loop over async items with for-of and async iteration.
for await (const item of asyncIterator()) { console.log(item); }
Tip: Use
Promise.all()for independent async operations to run them in parallel and get faster results.
Warning: Awaiting operations sequentially when they are independent will be slower than using
Promise.all()for parallel execution.