Working with Promises: From Basics to Advanced
A comprehensive guide to JavaScript Promises covering creation, chaining, error handling, and advanced patterns.
What is a Promise?
A Promise is an object representing the eventual completion or failure of an asynchronous operation. Think of it as a placeholder for a value that will be available in the future.
Promise States
A Promise can be in one of three states: - Pending: Initial state, neither fulfilled nor rejected - Fulfilled: Operation completed successfully - Rejected: Operation failed
``javascript
const promise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('Operation succeeded!');
} else {
reject(new Error('Operation failed!'));
}
});
`
Consuming Promises
.then() and .catch()
`javascript
fetch('/api/users')
.then(response => response.json())
.then(users => {
console.log('Users:', users);
})
.catch(error => {
console.error('Failed to fetch users:', error);
})
.finally(() => {
console.log('Request completed');
});
`
Promise Chaining
Each .then() returns a new Promise, enabling clean sequential async operations:
`javascript
function getUser(id) {
return fetch(\/api/users/\${id}\)
.then(res => res.json());
}
function getUserPosts(userId) {
return fetch(\/api/users/\${userId}/posts\)
.then(res => res.json());
}
getUser(1)
.then(user => {
console.log('User:', user.name);
return getUserPosts(user.id);
})
.then(posts => {
console.log('Posts:', posts.length);
})
.catch(error => {
console.error('Error:', error);
});
`
Static Promise Methods
Promise.all() — Wait for All
`javascript
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())
]);
// All three requests run in parallel
// Rejects if ANY promise rejects
`
Promise.allSettled() — Wait for All (No Short-Circuit)
`javascript
const results = await Promise.allSettled([
fetch('/api/fast'),
fetch('/api/slow'),
fetch('/api/might-fail')
]);
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Success:', result.value);
} else {
console.log('Failed:', result.reason);
}
});
`
Promise.race() — First to Settle Wins
`javascript
// Timeout pattern
function fetchWithTimeout(url, ms) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
)
]);
}
const data = await fetchWithTimeout('/api/data', 5000);
`
Promise.any() — First to Fulfill Wins
`javascript
// Try multiple mirrors, use first successful one
const response = await Promise.any([
fetch('https://mirror1.example.com/data'),
fetch('https://mirror2.example.com/data'),
fetch('https://mirror3.example.com/data')
]);
`
Error Handling Patterns
Centralized Error Handling
`javascript
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(\HTTP \${response.status}: \${response.statusText}\);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else if (error instanceof TypeError) {
console.error('Network error:', error.message);
} else {
console.error('Unexpected error:', error);
}
throw error;
}
}
`
Retry Pattern
`javascript
async function fetchWithRetry(url, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url).then(r => r.json());
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(r => setTimeout(r, delay * (i + 1)));
}
}
}
`
Advanced Patterns
Sequential Execution
`javascript
async function processSequentially(items, asyncFn) {
const results = [];
for (const item of items) {
results.push(await asyncFn(item));
}
return results;
}
`
Concurrent with Limit
`javascript
async function mapWithConcurrency(items, fn, concurrency = 5) {
const results = [];
const executing = new Set();
for (const item of items) { const p = fn(item).then(result => { executing.delete(p); return result; }); executing.add(p); results.push(p);
if (executing.size >= concurrency) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
`
Summary
Promises are fundamental to modern JavaScript async programming. Master the static methods (all, allSettled, race, any`), understand error propagation through chains, and use the advanced patterns for production-grade code.