The Problem with Callbacks
Before Promises, asynchronous JavaScript relied on callbacks, leading to deeply nested code known as "callback hell." Promises provide a cleaner, more maintainable approach.
Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('Operation completed!');
} else {
reject(new Error('Something went wrong'));
}
});
myPromise
.then(result => console.log(result))
.catch(error => console.error(error));
Real-World Promise: Fetching Data
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({ id: userId, name: 'John Doe', email: 'john@example.com' });
} else {
reject(new Error('Invalid user ID'));
}
}, 1000);
});
}
fetchUserData(1)
.then(user => {
console.log('User:', user);
return fetchUserData(user.id);
})
.then(updatedUser => console.log('Updated:', updatedUser))
.catch(error => console.error('Error:', error.message));
Promise Chaining
Each .then() returns a new Promise, allowing you to chain operations cleanly.
fetch('/api/user')
.then(response => response.json())
.then(user => fetch(`/api/posts/${user.id}`))
.then(response => response.json())
.then(posts => console.log(posts))
.catch(error => console.error('Chain failed:', error));
Promise.all — Run in Parallel
const promise1 = fetch('/api/users').then(r => r.json());
const promise2 = fetch('/api/posts').then(r => r.json());
const promise3 = fetch('/api/comments').then(r => r.json());
Promise.all([promise1, promise2, promise3])
.then(([users, posts, comments]) => {
console.log({ users, posts, comments });
})
.catch(error => {
console.error('One of the promises failed:', error);
});
Promise.race — First One Wins
const fastAPI = fetch('/api/fast-endpoint');
const slowAPI = fetch('/api/slow-endpoint');
Promise.race([fastAPI, slowAPI])
.then(response => {
console.log('Winner:', response.url);
});
Promise.any — First Success Wins
Promise.any([
Promise.reject('Error 1'),
Promise.reject('Error 2'),
Promise.resolve('Success!')
]).then(result => {
console.log(result); // 'Success!'
}).catch(errors => {
console.log('All failed:', errors);
});
Converting Callbacks to Promises
const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
// Now you can use:
const data = await readFileAsync('file.txt', 'utf8');