What Is Async/Await?
Async/await is JavaScript’s cleanest syntax for working with asynchronous operations — network requests, file I/O, database queries, timers. Introduced in ES2017 (ES8), it makes async code read like synchronous code:
📋 Table of Contents
async— marks a function as asynchronous; always returns a Promiseawait— pauses execution inside an async function until a Promise settles
await somePromise is equivalent to somePromise.then(result => ...). Same mechanism, cleaner syntax.Promises First: The Foundation
Before async/await, you chained Promises with .then(). Understanding this makes async/await click:
// Promise chain — works, but nests deeply
fetch('https://api.example.com/users/1')
.then(response => response.json())
.then(user => fetch('https://api.example.com/posts?userId=' + user.id))
.then(response => response.json())
.then(posts => console.log(posts))
.catch(error => console.error('Failed:', error));
// Same logic with async/await — flat and readable
async function getUserPosts(userId) {
const userRes = await fetch('https://api.example.com/users/' + userId);
const user = await userRes.json();
const postsRes = await fetch('https://api.example.com/posts?userId=' + user.id);
const posts = await postsRes.json();
return posts;
}
Your First async Function
async function getUser(id) {
const response = await fetch('https://jsonplaceholder.typicode.com/users/' + id);
if (!response.ok) throw new Error('HTTP error: ' + response.status);
return response.json();
}
const user = await getUser(1);
console.log(user.name); // "Leanne Graham"
Key rules: An async function always returns a Promise. await only works inside async functions. If an awaited Promise rejects, it propagates as a thrown error.
Error Handling with try/catch
async function fetchUserData(userId) {
try {
const response = await fetch('/api/users/' + userId);
if (!response.ok) throw new Error('Server error: ' + response.status);
return await response.json();
} catch (error) {
if (error.name === 'TypeError') {
console.error('Network error:', error.message);
} else {
console.error('API error:', error.message);
}
return null;
}
}
// Per-await error handling
async function loadDashboard() {
const user = await fetchUserData(1).catch(() => null);
const stats = await fetchStats().catch(() => ({ views: 0 }));
const alerts = await fetchAlerts().catch(() => []);
return { user, stats, alerts };
}
Parallel Execution with Promise.all()
Sequential awaits run one-at-a-time. Use Promise.all() to fire multiple Promises simultaneously:
// ❌ Sequential — 3 seconds total (1s + 1s + 1s)
async function loadSequential() {
const users = await fetchUsers(); // waits 1s
const posts = await fetchPosts(); // waits another 1s
const photos = await fetchPhotos(); // waits another 1s
return { users, posts, photos };
}
// ✅ Parallel — ~1 second total (all fire at once)
async function loadParallel() {
const [users, posts, photos] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchPhotos()
]);
return { users, posts, photos };
}
// Promise.allSettled — get results even if some fail
async function loadWithFallbacks() {
const results = await Promise.allSettled([fetchUsers(), fetchPosts(), fetchPhotos()]);
return results.map(r => r.status === 'fulfilled' ? r.value : null);
}
// Promise.race — first wins (timeout pattern)
async function fetchWithTimeout(url, ms = 5000) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Request timed out')), ms)
);
return Promise.race([fetch(url), timeout]);
}
Async Loops: The Right Way
const userIds = [1, 2, 3, 4, 5];
// ❌ forEach DOES NOT await — requests fire but nothing waits
userIds.forEach(async (id) => {
const user = await fetchUser(id); // fires immediately without waiting
console.log(user.name);
});
// ✅ for...of — sequential (each awaits before next starts)
for (const id of userIds) {
const user = await fetchUser(id);
console.log(user.name);
}
// ✅ Promise.all + map — parallel (all fire simultaneously)
const users = await Promise.all(userIds.map(id => fetchUser(id)));
users.forEach(u => console.log(u.name));
// ✅ Batched parallel (avoid overwhelming the server)
async function batchProcess(ids, batchSize = 5) {
const results = [];
for (let i = 0; i < ids.length; i += batchSize) {
const batch = ids.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(id => fetchUser(id)));
results.push(...batchResults);
}
return results;
}
Advanced Patterns
Async IIFE
// Async IIFE — top-level await not available? Use this
(async () => {
const config = await loadConfig();
await startServer(config);
console.log('Server running on port', config.port);
})();
Async Generator (streaming)
async function* streamLargeDataset(url) {
let page = 1;
while (true) {
const response = await fetch(url + '?page=' + page);
const data = await response.json();
if (!data.items.length) break;
yield data.items;
page++;
}
}
// Consume with for-await-of
for await (const items of streamLargeDataset('/api/records')) {
processItems(items);
}
Retry with Exponential Backoff
async function fetchWithRetry(url, options = {}, retries = 3, backoff = 1000) {
try {
const res = await fetch(url, options);
if (!res.ok && res.status >= 500 && retries > 0) {
await new Promise(r => setTimeout(r, backoff));
return fetchWithRetry(url, options, retries - 1, backoff * 2);
}
return res;
} catch (err) {
if (retries > 0) {
await new Promise(r => setTimeout(r, backoff));
return fetchWithRetry(url, options, retries - 1, backoff * 2);
}
throw err;
}
}
Common Mistakes
- Forgetting
await— you get a pending Promise, not a value - async in forEach — use
for...oforPromise.allinstead - Sequential awaits when parallel is possible — unnecessary serialization kills performance
- Swallowing errors — empty catch blocks hide bugs. Log or rethrow.
// ❌ Missing await — user is a Promise, not an object
async function broken() {
const user = fetchUser(1); // missing await!
console.log(user.name); // undefined — user is a Promise
}
// ✅ Fixed
async function fixed() {
const user = await fetchUser(1);
console.log(user.name); // "Leanne Graham"
}
Real-World API Pattern
A production-ready API client with timeout and error handling:
class ApiClient {
constructor(baseUrl, options = {}) {
this.baseUrl = baseUrl;
this.timeout = options.timeout || 10000;
}
async request(path, options = {}) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(this.baseUrl + path, {
...options,
signal: controller.signal,
headers: { 'Content-Type': 'application/json', ...options.headers }
});
clearTimeout(timeoutId);
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw Object.assign(new Error(err.message || 'HTTP ' + response.status), {
status: response.status, body: err
});
}
return response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') throw new Error('Request timed out');
throw error;
}
}
async get(path) { return this.request(path); }
async post(path, body) { return this.request(path, { method: 'POST', body: JSON.stringify(body) }); }
}
const api = new ApiClient('https://api.example.com', { timeout: 8000 });
const user = await api.get('/users/1');
🚀 Level Up Your JavaScript
Async/await is one of the most important modern JS patterns. Explore why TypeScript makes async patterns even safer, or check all programming guides for more deep dives.
Frequently Asked Questions
What is async/await?
Syntactic sugar over Promises. async marks a function async; await pauses it until a Promise settles. Makes async code read like sync code.
Difference between async/await and Promises?
Same mechanism, cleaner syntax. Use async/await for readability; use raw Promises for Promise.all(), Promise.race().
How to handle errors?
Use try/catch blocks. Or append .catch() to individual awaited Promises.
How to run operations in parallel?
await Promise.all([p1, p2, p3]) — fires all simultaneously.
async/await in forEach?
No — forEach ignores async callbacks. Use for...of or Promise.all(arr.map(async x => ...)).
What is top-level await?
ES2022 — use await at module top level without async wrapper. ES modules only.
📚 You might also like
🔗 Share this article




✍️ Leave a Comment