Skip to content
Plurafy

Promises and Async/Await

Managing asynchronous operations with Promises and async/await

You need to fetch data from multiple APIs in sequence, then process the results. The old callback approach leads to callback hell. How can you make this clean and readable?

Promises represent a value that may not be available yet but will be resolved eventually. They provide a cleaner alternative to callbacks and are the foundation for async/await syntax.

// Creating a Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then(
result => console.log(result), // Success!
error => console.log('Error:', error)
);
// Or using catch
promise
.then(result => console.log(result))
.catch(error => console.log('Error:', error));
// ❌ Callback Hell
function fetchData(callback) {
fetch('/api/user').then(res => {
res.json().then(user => {
fetch(`/api/posts/${user.id}`).then(res => {
res.json().then(posts => {
fetch(`/api/comments/${posts[0].id}`).then(res => {
res.json().then(comments => {
callback(user, posts, comments);
});
});
});
});
});
});
}
// ✅ Using Promises
function fetchDataWithPromises() {
return fetch('/api/user')
.then(res => res.json())
.then(user => {
return fetch(`/api/posts/${user.id}`)
.then(res => res.json())
.then(posts => ({ user, posts }));
})
.then(({ user, posts }) => {
return fetch(`/api/comments/${posts[0].id}`)
.then(res => res.json())
.then(comments => ({ user, posts, comments }));
});
}
// ✅ Using Async/Await (Cleanest)
async function fetchDataWithAsync() {
const userRes = await fetch('/api/user');
const user = await userRes.json();
const postsRes = await fetch(`/api/posts/${user.id}`);
const posts = await postsRes.json();
const commentsRes = await fetch(`/api/comments/${posts[0].id}`);
const comments = await commentsRes.json();
return { user, posts, comments };
}
// Usage
fetchDataWithAsync()
.then(data => console.log(data))
.catch(error => console.error(error));
// A promise can be in one of three states:
// 1. PENDING: Initial state
const pending = new Promise(resolve => {
// Still waiting...
});
// 2. FULFILLED: Resolved with value
const fulfilled = new Promise(resolve => {
resolve('Done!');
});
// 3. REJECTED: Rejected with reason
const rejected = new Promise((resolve, reject) => {
reject(new Error('Failed!'));
});
// Once settled (fulfilled or rejected), state cannot change
const promise = new Promise(resolve => {
resolve('First');
resolve('Second'); // Ignored - already settled
});
promise.then(value => console.log(value)); // "First"
// Promise.all - Wait for all promises
Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
])
.then(([user, posts, comments]) => {
console.log(user, posts, comments);
})
.catch(error => console.log('One promise failed:', error));
// Promise.race - First promise wins
Promise.race([
fetch('/api/fast'),
fetch('/api/slow')
]).then(winner => console.log(winner));
// Promise.allSettled - All results regardless of success
Promise.allSettled([
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
]).then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
});
// Promise.any - First fulfilled promise
Promise.any([
Promise.reject('error1'),
Promise.resolve('success'),
Promise.reject('error2')
]).then(winner => console.log(winner)); // "success"
// Using try/catch
async function fetchUserData() {
try {
const user = await fetchUser();
const posts = await fetchPosts(user.id);
return { user, posts };
} catch (error) {
console.error('Failed to fetch data:', error);
throw error; // Re-throw if needed
} finally {
console.log('Cleanup code here');
}
}
// Handling specific errors
async function robustFetch() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
if (error instanceof TypeError) {
console.log('Network error:', error);
} else {
console.log('Other error:', error);
}
}
}
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve()
.then(() => console.log('3'))
.then(() => console.log('4'));
console.log('5');
// Output: 1, 5, 3, 4, 2
// Why? Sync -> Microtask Queue (Promises) -> Macrotask Queue (setTimeout)