Promise.all() is a static method of the Promise class that takes an array of promises and returns a new promise. This new promise resolves when all promises in the array are fulfilled, or rejects if at least one of the promises is rejected. Its main purpose is to execute multiple asynchronous operations in parallel and get their results in one place.
Promise.all() is a powerful tool for working with multiple asynchronous operations simultaneously. It takes an iterable object (usually an array) of promises and returns a new promise that:
const promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => {
console.log(results); // [1, 2, 3]
})
.catch(error => {
console.error(error);
});
The main advantage of Promise.all() is the ability to execute multiple asynchronous operations in parallel rather than sequentially, which significantly speeds up execution:
// Sequential execution (slow)
async function sequential() {
const start = Date.now();
const result1 = await fetch('/api/data1');
const data1 = await result1.json();
const result2 = await fetch('/api/data2');
const data2 = await result2.json();
const result3 = await fetch('/api/data3');
const data3 = await result3.json();
console.log('Execution time:', Date.now() - start);
return [data1, data2, data3];
}
// Parallel execution with Promise.all() (fast)
async function parallel() {
const start = Date.now();
const [data1, data2, data3] = await Promise.all([
fetch('/api/data1').then(res => res.json()),
fetch('/api/data2').then(res => res.json()),
fetch('/api/data3').then(res => res.json())
]);
console.log('Execution time:', Date.now() - start);
return [data1, data2, data3];
}
Promise.all() allows you to wait for all necessary operations to complete before continuing code execution:
async function loadUserData(userId) {
// Load user profile, posts, and friends in parallel
const [userProfile, userPosts, userFriends] = await Promise.all([
fetchUserProfile(userId),
fetchUserPosts(userId),
fetchUserFriends(userId)
]);
// Continue only when all data is loaded
renderUserPage(userProfile, userPosts, userFriends);
}
Promise.all() is ideal for asynchronous processing of data arrays:
async function processItems(items) {
// Create an array of promises for each item
const promises = items.map(item => processItem(item));
// Process all items in parallel
const results = await Promise.all(promises);
return results;
}
async function processItem(item) {
// Asynchronous processing of a single item
await new Promise(resolve => setTimeout(resolve, 100));
return item * 2;
}
// Usage
processItems([1, 2, 3, 4, 5])
.then(results => console.log(results)); // [2, 4, 6, 8, 10]
Promise.all() has “fail-fast” behavior — it rejects as soon as any of the promises rejects:
const promises = [
Promise.resolve(1),
Promise.reject(new Error('Something went wrong')),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => {
console.log(results); // This code won't execute
})
.catch(error => {
console.error(error); // Error: Something went wrong
});
If you need to get the results of all promises regardless of their status, use Promise.allSettled()
.
Promise.all() preserves the order of results according to the order of the original promises, even if they complete in a different order:
const promise1 = new Promise(resolve => setTimeout(() => resolve('first'), 300));
const promise2 = new Promise(resolve => setTimeout(() => resolve('second'), 200));
const promise3 = new Promise(resolve => setTimeout(() => resolve('third'), 100));
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // ['first', 'second', 'third']
});
If an empty array is passed, Promise.all() will immediately resolve with an empty array of results:
Promise.all([])
.then(results => {
console.log(results); // []
});
If there are non-promises in the array, they are automatically wrapped in Promise.resolve():
Promise.all([1, Promise.resolve(2), 3])
.then(results => {
console.log(results); // [1, 2, 3]
});
const promises = [
new Promise(resolve => setTimeout(() => resolve('fast'), 100)),
new Promise(resolve => setTimeout(() => resolve('medium'), 200)),
new Promise(resolve => setTimeout(() => resolve('slow'), 300))
];
Promise.race(promises)
.then(result => console.log(result)); // 'fast'
const promises = [
Promise.resolve('success'),
Promise.reject('error'),
Promise.resolve('another success')
];
Promise.allSettled(promises)
.then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 'success' },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 'another success' }
// ]
});
const promises = [
Promise.reject('error 1'),
Promise.resolve('success'),
Promise.reject('error 2')
];
Promise.any(promises)
.then(result => console.log(result)); // 'success'
async function loadDashboardData() {
try {
const [userData, statsData, notificationsData] = await Promise.all([
fetchUserData(),
fetchStatistics(),
fetchNotifications()
]);
renderDashboard(userData, statsData, notificationsData);
} catch (error) {
showErrorMessage('Failed to load dashboard data');
console.error(error);
}
}
async function loadAndProcessImages(imageUrls) {
const imagePromises = imageUrls.map(async url => {
const response = await fetch(url);
const blob = await response.blob();
return processImage(blob);
});
return Promise.all(imagePromises);
}
function processImage(blob) {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
// Process the image
const processedImage = applyFilters(img);
resolve(processedImage);
};
img.src = URL.createObjectURL(blob);
});
}
async function validateForm(formData) {
const validationPromises = [
validateUsername(formData.username),
validateEmail(formData.email),
validatePassword(formData.password),
checkUsernameAvailability(formData.username)
];
try {
await Promise.all(validationPromises);
return { valid: true };
} catch (error) {
return { valid: false, error: error.message };
}
}
// Limiting the number of parallel requests
async function processInBatches(items, batchSize = 5) {
const results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchPromises = batch.map(item => processItem(item));
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
}
return results;
}
// ❌ Bad - ignoring errors
Promise.all(promises).then(results => {
// What if an error occurs?
});
// ✅ Good - error handling
Promise.all(promises)
.then(results => {
// Process results
})
.catch(error => {
// Handle errors
});
Promise.all() is a powerful tool for parallel execution of asynchronous operations in JavaScript. It allows you to significantly speed up the execution of independent tasks, synchronize dependent operations, and efficiently process data arrays. Understanding the features and limitations of Promise.all(), as well as its differences from other Promise methods, allows you to create more efficient and reliable asynchronous code.
When used correctly with appropriate error handling, Promise.all() becomes an indispensable tool in every JavaScript developer’s arsenal, especially when working with APIs, processing data, and creating modern web applications.