Skip to main content

Github

JavaScript Async/Await: A Comprehensive Guide

Async/Await in JavaScript #

Async/await is syntactic sugar built on top of Promises, making asynchronous code look and behave more like synchronous code.

Async Functions #

An async function always returns a Promise:

// Async function declaration
async function fetchData() {
 return "data";
}
// Equivalent to:
function fetchData() {
 return Promise.resolve("data");
}
// Using async functions
fetchData().then(data => {
 console.log(data); // "data"
});
// Async arrow function
const getData = async () => {
 return "data";
};

Await Keyword #

Await pauses execution until a Promise is resolved:

async function fetchUser(id) {
 // Wait for the fetch to complete
 const response = await fetch(`/api/users/${id}`);
 const user = await response.json();
 return user;
}
// Without await (for comparison)
function fetchUser(id) {
 return fetch(`/api/users/${id}`)
 .then(response => response.json())
 .then(user => user);
}

Error Handling #

Use try/catch for error handling with async/await:

async function fetchData() {
 try {
 const response = await fetch('/api/data');
 
 if (!response.ok) {
 throw new Error(`HTTP error! status: ${response.status}`);
 }
 
 const data = await response.json();
 return data;
 } catch (error) {
 console.error('Failed to fetch data:', error);
 throw error; // Re-throw if needed
 }
}
// Using the function
async function main() {
 try {
 const data = await fetchData();
 console.log('Data:', data);
 } catch (error) {
 console.log('Error in main:', error.message);
 }
}

Multiple Async Operations #

Handle multiple async operations efficiently:

// Sequential execution (slower)
async function sequential() {
 const user = await fetchUser(1);
 const posts = await fetchPosts(user.id);
 const comments = await fetchComments(posts[0].id);
 return { user, posts, comments };
}
// Parallel execution (faster)
async function parallel() {
 const [user, posts, comments] = await Promise.all([
 fetchUser(1),
 fetchPosts(1),
 fetchComments(1)
 ]);
 return { user, posts, comments };
}
// Race - returns first resolved promise
async function fastest() {
 const result = await Promise.race([
 fetchFromServer1(),
 fetchFromServer2(),
 fetchFromServer3()
 ]);
 return result;
}
// allSettled - wait for all regardless of success/failure
async function allResults() {
 const results = await Promise.allSettled([
 fetchUser(1),
 fetchUser(2),
 fetchUser(3)
 ]);
 
 results.forEach((result, index) => {
 if (result.status === 'fulfilled') {
 console.log(`User ${index}:`, result.value);
 } else {
 console.log(`User ${index} failed:`, result.reason);
 }
 });
}

Async Iteration #

Process async operations in loops:

// Using for...of with await
async function processUsers(userIds) {
 for (const id of userIds) {
 const user = await fetchUser(id);
 console.log(user);
 }
}
// Using for await...of with async iterables
async function* asyncGenerator() {
 yield await Promise.resolve(1);
 yield await Promise.resolve(2);
 yield await Promise.resolve(3);
}
async function consume() {
 for await (const value of asyncGenerator()) {
 console.log(value);
 }
}
// Parallel processing with map
async function processAllUsers(userIds) {
 const promises = userIds.map(id => fetchUser(id));
 const users = await Promise.all(promises);
 return users;
}

Top-Level Await #

Use await at the top level in modules:

// In ES modules (with "type": "module" in package.json)
const response = await fetch('/api/config');
const config = await response.json();
export const API_URL = config.apiUrl;
export const TIMEOUT = config.timeout;
// Top-level await blocks module loading
// Dependents wait until this module resolves

Best Practices #

Tips for effective async/await usage:

// 1. Always return from async functions
async function good() {
 const data = await fetch('/api/data');
 return data; // Explicit return
}
// 2. Avoid mixing async/await with .then()
// Bad
async function mixed() {
 return await fetch('/api/data').then(r => r.json());
}
// Good
async function clean() {
 const response = await fetch('/api/data');
 return await response.json();
}
// 3. Use Promise.all for independent operations
async function optimized() {
 const [users, products] = await Promise.all([
 fetchUsers(),
 fetchProducts()
 ]);
 return { users, products };
}
// 4. Create utility functions for common patterns
async function withTimeout(promise, ms) {
 const timeout = new Promise((_, reject) =>
 setTimeout(() => reject(new Error('Timeout')), ms)
 );
 return Promise.race([promise, timeout]);
}
// Usage
const data = await withTimeout(fetchData(), 5000);

Related

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /