JavaScript Promises provide powerful methods for handling async operations. Here's a comprehensive guide to all Promise methods.
Promise.all()#
1// Wait for all promises to resolve
2const promise1 = fetch('/api/users');
3const promise2 = fetch('/api/posts');
4const promise3 = fetch('/api/comments');
5
6const [users, posts, comments] = await Promise.all([
7 promise1.then(r => r.json()),
8 promise2.then(r => r.json()),
9 promise3.then(r => r.json()),
10]);
11
12// Fails fast - rejects if ANY promise rejects
13try {
14 const results = await Promise.all([
15 Promise.resolve(1),
16 Promise.reject(new Error('Failed')),
17 Promise.resolve(3),
18 ]);
19} catch (error) {
20 console.log(error.message); // 'Failed'
21}
22
23// Practical: Parallel API calls
24async function fetchUserData(userId) {
25 const [user, posts, followers] = await Promise.all([
26 fetchUser(userId),
27 fetchUserPosts(userId),
28 fetchUserFollowers(userId),
29 ]);
30
31 return { user, posts, followers };
32}Promise.allSettled()#
1// Wait for all promises regardless of success/failure
2const results = await Promise.allSettled([
3 Promise.resolve('Success'),
4 Promise.reject(new Error('Failed')),
5 Promise.resolve('Another success'),
6]);
7
8// Results array contains status of each
9results.forEach((result, index) => {
10 if (result.status === 'fulfilled') {
11 console.log(`Promise ${index}: ${result.value}`);
12 } else {
13 console.log(`Promise ${index}: ${result.reason.message}`);
14 }
15});
16
17// Practical: Batch operations with error handling
18async function sendNotifications(users) {
19 const promises = users.map(user =>
20 sendNotification(user.id, user.message)
21 );
22
23 const results = await Promise.allSettled(promises);
24
25 const succeeded = results.filter(r => r.status === 'fulfilled').length;
26 const failed = results.filter(r => r.status === 'rejected').length;
27
28 console.log(`Sent: ${succeeded}, Failed: ${failed}`);
29
30 return results;
31}Promise.race()#
1// First promise to settle wins
2const fastest = await Promise.race([
3 fetch('/api/server1'),
4 fetch('/api/server2'),
5 fetch('/api/server3'),
6]);
7
8// Timeout pattern
9function withTimeout(promise, ms) {
10 const timeout = new Promise((_, reject) =>
11 setTimeout(() => reject(new Error('Timeout')), ms)
12 );
13
14 return Promise.race([promise, timeout]);
15}
16
17// Usage
18try {
19 const data = await withTimeout(fetch('/api/slow'), 5000);
20 console.log('Got data:', data);
21} catch (error) {
22 console.log('Request timed out');
23}
24
25// First to reject also wins
26const result = await Promise.race([
27 new Promise(resolve => setTimeout(() => resolve('slow'), 1000)),
28 Promise.reject(new Error('instant fail')),
29]); // Rejects immediatelyPromise.any()#
1// First promise to FULFILL wins (ignores rejections)
2const first = await Promise.any([
3 Promise.reject(new Error('Error 1')),
4 Promise.resolve('Success'),
5 Promise.reject(new Error('Error 2')),
6]);
7
8console.log(first); // 'Success'
9
10// Only rejects if ALL promises reject
11try {
12 await Promise.any([
13 Promise.reject(new Error('Error 1')),
14 Promise.reject(new Error('Error 2')),
15 ]);
16} catch (error) {
17 console.log(error.name); // 'AggregateError'
18 console.log(error.errors); // [Error, Error]
19}
20
21// Practical: Try multiple sources
22async function fetchFromAnySource(urls) {
23 const promises = urls.map(url =>
24 fetch(url).then(r => {
25 if (!r.ok) throw new Error(`HTTP ${r.status}`);
26 return r.json();
27 })
28 );
29
30 return Promise.any(promises);
31}Promise.resolve() & Promise.reject()#
1// Create resolved promise
2const resolved = Promise.resolve('value');
3const resolvedObj = Promise.resolve({ data: 'test' });
4
5// Resolve another promise (unwraps it)
6const nested = Promise.resolve(Promise.resolve('unwrapped'));
7console.log(await nested); // 'unwrapped'
8
9// Create rejected promise
10const rejected = Promise.reject(new Error('Failed'));
11
12// Practical: Normalize sync/async functions
13function maybeAsync(value) {
14 if (typeof value.then === 'function') {
15 return value; // Already a promise
16 }
17 return Promise.resolve(value);
18}
19
20// Cache with promises
21const cache = new Map();
22
23function fetchWithCache(url) {
24 if (cache.has(url)) {
25 return Promise.resolve(cache.get(url));
26 }
27
28 return fetch(url)
29 .then(r => r.json())
30 .then(data => {
31 cache.set(url, data);
32 return data;
33 });
34}Promise.withResolvers()#
1// Create deferred promise (ES2024)
2const { promise, resolve, reject } = Promise.withResolvers();
3
4// External control over resolution
5setTimeout(() => resolve('Done!'), 1000);
6
7const result = await promise; // 'Done!'
8
9// Practical: Event-based resolution
10function waitForEvent(element, event) {
11 const { promise, resolve } = Promise.withResolvers();
12
13 element.addEventListener(event, resolve, { once: true });
14
15 return promise;
16}
17
18const click = await waitForEvent(button, 'click');Chaining Promises#
1// Basic chain
2fetch('/api/user')
3 .then(response => response.json())
4 .then(user => fetch(`/api/posts?userId=${user.id}`))
5 .then(response => response.json())
6 .then(posts => console.log(posts))
7 .catch(error => console.error(error));
8
9// Return values pass through chain
10Promise.resolve(1)
11 .then(x => x + 1) // 2
12 .then(x => x * 2) // 4
13 .then(x => x + 3) // 7
14 .then(console.log); // 7
15
16// Throwing in then creates rejection
17Promise.resolve('test')
18 .then(value => {
19 throw new Error('Oops');
20 })
21 .catch(error => {
22 console.log(error.message); // 'Oops'
23 });Error Handling#
1// catch() handles rejections
2fetch('/api/data')
3 .then(r => r.json())
4 .catch(error => {
5 console.error('Fetch failed:', error);
6 return { fallback: true };
7 })
8 .then(data => console.log(data));
9
10// finally() runs regardless
11fetch('/api/data')
12 .then(r => r.json())
13 .catch(error => console.error(error))
14 .finally(() => {
15 console.log('Cleanup');
16 hideLoadingSpinner();
17 });
18
19// Multiple catch blocks
20fetch('/api/data')
21 .then(r => {
22 if (!r.ok) throw new Error(`HTTP ${r.status}`);
23 return r.json();
24 })
25 .catch(error => {
26 // Handle HTTP errors
27 if (error.message.startsWith('HTTP')) {
28 return fetchFallback();
29 }
30 throw error; // Re-throw others
31 })
32 .catch(error => {
33 // Handle all other errors
34 console.error('Unhandled:', error);
35 });Concurrent Patterns#
1// Limit concurrency
2async function mapLimit(items, limit, fn) {
3 const results = [];
4 const executing = new Set();
5
6 for (const [index, item] of items.entries()) {
7 const promise = fn(item, index).then(result => {
8 executing.delete(promise);
9 return result;
10 });
11
12 results.push(promise);
13 executing.add(promise);
14
15 if (executing.size >= limit) {
16 await Promise.race(executing);
17 }
18 }
19
20 return Promise.all(results);
21}
22
23// Usage
24await mapLimit(urls, 3, async (url) => {
25 const response = await fetch(url);
26 return response.json();
27});
28
29// Sequential execution
30async function sequential(items, fn) {
31 const results = [];
32 for (const item of items) {
33 results.push(await fn(item));
34 }
35 return results;
36}Creating Promises#
1// Basic promise constructor
2const promise = new Promise((resolve, reject) => {
3 // Async operation
4 setTimeout(() => {
5 const success = Math.random() > 0.5;
6 if (success) {
7 resolve('Success!');
8 } else {
9 reject(new Error('Failed!'));
10 }
11 }, 1000);
12});
13
14// Promisify callback-based function
15function promisify(fn) {
16 return (...args) => {
17 return new Promise((resolve, reject) => {
18 fn(...args, (error, result) => {
19 if (error) reject(error);
20 else resolve(result);
21 });
22 });
23 };
24}
25
26// Usage
27const readFile = promisify(fs.readFile);
28const content = await readFile('file.txt', 'utf8');Practical Patterns#
1// Retry with exponential backoff
2async function retry(fn, maxAttempts = 3, delay = 1000) {
3 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
4 try {
5 return await fn();
6 } catch (error) {
7 if (attempt === maxAttempts) throw error;
8 await new Promise(r => setTimeout(r, delay * attempt));
9 }
10 }
11}
12
13// Debounce async
14function debounceAsync(fn, wait) {
15 let timeout;
16 let pending;
17
18 return (...args) => {
19 clearTimeout(timeout);
20
21 return new Promise((resolve, reject) => {
22 timeout = setTimeout(async () => {
23 try {
24 const result = await fn(...args);
25 resolve(result);
26 } catch (error) {
27 reject(error);
28 }
29 }, wait);
30 });
31 };
32}Best Practices#
Error Handling:
✓ Always add catch handlers
✓ Use finally for cleanup
✓ Re-throw when appropriate
✓ Log unexpected errors
Patterns:
✓ Use Promise.all for parallel
✓ Use Promise.allSettled for batch
✓ Use Promise.race for timeout
✓ Use Promise.any for redundancy
Performance:
✓ Start promises early
✓ Limit concurrency
✓ Avoid unnecessary awaits
✓ Use parallel when possible
Avoid:
✗ Unhandled rejections
✗ Nesting promises unnecessarily
✗ Mixing callbacks and promises
✗ Forgetting to return promises
Conclusion#
Promise methods provide powerful tools for managing async operations. Use Promise.all() for parallel execution, Promise.allSettled() when you need all results regardless of failures, Promise.race() for timeouts, and Promise.any() for redundant sources. Always handle errors appropriately and consider concurrency limits for batch operations.