Chapter 6: Asynchronous Programming Advanced
Chapter 6 of 15
Chapter 6: Asynchronous Programming Advanced
6.1 Promises Advanced
Promises provide a cleaner way to handle asynchronous operations. Understanding advanced Promise patterns is essential for modern JavaScript development.
Promise.all() - Wait for All:
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // [3, 42, "foo"]
})
.catch(error => {
console.error(error); // If any promise rejects
});
Promise.allSettled() - Wait for All (Even Rejected):
const promises = [
Promise.resolve('success'),
Promise.reject('error'),
Promise.resolve('another success')
];
Promise.allSettled(promises)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index}:`, result.value);
} else {
console.log(`Promise ${index}:`, result.reason);
}
});
});
Promise.race() - First to Resolve/Reject:
const promise1 = new Promise((resolve) =>
setTimeout(resolve, 500, 'First'));
const promise2 = new Promise((resolve) =>
setTimeout(resolve, 100, 'Second'));
Promise.race([promise1, promise2])
.then(value => {
console.log(value); // "Second" - fastest
});
Promise Chaining:
fetch('/api/user')
.then(response => response.json())
.then(user => {
return fetch(`/api/posts/${user.id}`);
})
.then(response => response.json())
.then(posts => {
console.log(posts);
})
.catch(error => {
console.error('Error:', error);
});
6.2 Async/Await Patterns
Async/await provides a more readable way to write asynchronous code, making it look like synchronous code.
// Basic async/await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
return user;
} catch (error) {
console.error('Error fetching user:', error);
throw error;
}
}
Parallel Execution:
async function fetchMultipleData() {
try {
// Execute promises in parallel
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
return { users, posts, comments };
} catch (error) {
console.error('Error:', error);
}
}
Sequential Execution:
async function processSequentially() {
const step1 = await doStep1();
const step2 = await doStep2(step1);
const step3 = await doStep3(step2);
return step3;
}
Error Handling Patterns:
// Pattern 1: Try-catch
async function withTryCatch() {
try {
const data = await fetchData();
return data;
} catch (error) {
// Handle error
return null;
}
}
// Pattern 2: Catch on promise
async function withCatch() {
const data = await fetchData().catch(error => {
console.error(error);
return null;
});
return data;
}
// Pattern 3: Wrapper function
function asyncHandler(fn) {
return function(req, res, next) {
Promise.resolve(fn(req, res, next))
.catch(next);
};
}
6.3 Advanced Promise Patterns
Retry Pattern:
async function retryOperation(fn, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Timeout Pattern:
function withTimeout(promise, timeoutMs) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), timeoutMs);
});
return Promise.race([promise, timeout]);
}
// Usage
const data = await withTimeout(
fetch('/api/data').then(r => r.json()),
5000 // 5 second timeout
);