// PROMISES
// Basic promise
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({id, name: 'John'});
} else {
reject('Invalid ID');
}
}, 1000);
});
}
// Using promises
fetchUser(1)
.then(user => {
console.log('User:', user);
return fetchPosts(user.id);
})
.then(posts => {
console.log('Posts:', posts);
return fetchComments(posts[0].id);
})
.then(comments => {
console.log('Comments:', comments);
})
.catch(error => {
console.error('Error:', error);
})
.finally(() => {
console.log('Cleanup');
});
// ASYNC/AWAIT
async function getUserData(id) {
try {
const user = await fetchUser(id);
console.log('User:', user);
const posts = await fetchPosts(user.id);
console.log('Posts:', posts);
const comments = await fetchComments(posts[0].id);
console.log('Comments:', comments);
return {user, posts, comments};
} catch (error) {
console.error('Error:', error);
throw error; // Re-throw if needed
} finally {
console.log('Cleanup');
}
}
// PARALLEL EXECUTION
// Promises - Promise.all
Promise.all([
fetchUser(1),
fetchPosts(1),
fetchComments(1)
])
.then(([user, posts, comments]) => {
console.log({user, posts, comments});
})
.catch(error => {
console.error('One failed:', error);
});
// Async/await - sequential (SLOW)
async function sequentialSlow() {
const user = await fetchUser(1); // Wait
const posts = await fetchPosts(1); // Then wait
const comments = await fetchComments(1); // Then wait
return {user, posts, comments};
}
// Total time: sum of all
// Async/await - parallel (FAST)
async function parallelFast() {
const [user, posts, comments] = await Promise.all([
fetchUser(1),
fetchPosts(1),
fetchComments(1)
]);
return {user, posts, comments};
}
// Total time: max of all
// Start promises, then await
async function parallelPattern() {
const userPromise = fetchUser(1);
const postsPromise = fetchPosts(1);
const commentsPromise = fetchComments(1);
const user = await userPromise;
const posts = await postsPromise;
const comments = await commentsPromise;
return {user, posts, comments};
}
// ERROR HANDLING COMPARISON
// Promises - catch chain
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.catch(error => {
// Catches any error in the chain
console.error(error);
});
// Async/await - try/catch
async function withErrorHandling() {
try {
const user = await fetchUser(1);
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts[0].id);
} catch (error) {
// Catches any error
console.error(error);
}
}
// Multiple try/catch for specific handling
async function specificErrorHandling() {
let user, posts;
try {
user = await fetchUser(1);
} catch (error) {
console.error('User fetch failed:', error);
return null;
}
try {
posts = await fetchPosts(user.id);
} catch (error) {
console.error('Posts fetch failed:', error);
posts = [];
}
return {user, posts};
}
// PROMISE COMBINATORS
// Promise.all - all must succeed
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results))
.catch(err => console.log('One failed'));
// Promise.allSettled - wait for all
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Success:', result.value);
} else {
console.log('Failed:', result.reason);
}
});
});
// Promise.race - first to finish
Promise.race([promise1, promise2])
.then(result => console.log('First:', result));
// Promise.any - first fulfilled
Promise.any([promise1, promise2, promise3])
.then(result => console.log('First success:', result));
// PRACTICAL PATTERNS
// Retry logic with promises
function retry(fn, retries = 3) {
return fn().catch(err => {
if (retries > 0) {
return retry(fn, retries - 1);
}
throw err;
});
}
// Retry logic with async/await
async function retryAsync(fn, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
}
}
}
// Timeout wrapper
function withTimeout(promise, ms) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject('Timeout'), ms)
)
]);
}
// Sequential processing
async function processSequentially(items) {
const results = [];
for (const item of items) {
const result = await processItem(item);
results.push(result);
}
return results;
}
// Parallel processing
async function processParallel(items) {
return Promise.all(
items.map(item => processItem(item))
);
}
// BEST PRACTICES
// Always return promises
async function good() {
return await fetchData(); // or just: return fetchData();
}
// Avoid unnecessary async
function unnecessary() { // Don't need async here
return fetchData(); // Already returns promise
}
// Handle errors
async function alwaysHandle() {
try {
return await fetchData();
} catch (error) {
console.error(error);
return null; // Provide fallback
}
}
// Use Promise.all for independent operations
async function efficient() {
return Promise.all([
fetchUser(),
fetchPosts(),
fetchSettings()
]);
}