Back to Blog
Tutorial2025-03-08

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.