- Published on
Mastering JavaScript Promise.all()
In this blog post, we will explore how Promise.all()
works in depth, and understand its syntax, and dive into real-world code examples to understand its potential.
Table of Contents
Understanding Promises
Before diving into Promise.all()
, it's essential to understand JavaScript Promises. In JavaScript promises are way for handling asynchronous operations.
A promise can exist in one of three states
- Pending
- Fulfilled
- Rejected
Initially, a promise is in the pending
state, indicating that the process is still ongoing and not yet completed. If the operation is successful, the promise transitions to the fulfilled
state. However, if an error occurs during the process, the promise transitions to the rejected
state.
Imagine you have a website that displays random images of animals. You want to fetch a new image from an API and display it on your website. You can use a promise to handle this asynchronous action.
Here's an example:
const fetchImage = new Promise((resolve, reject) => {
// Simulate fetching an image from an API
setTimeout(() => {
const imageURL = 'https://example.com/animal.jpg';
const error = false; // Set to true to simulate an error
if (!error) {
resolve(imageURL); // Promise is fulfilled
} else {
reject('Error fetching image'); // Promise is rejected
}
}, 2000); // Simulate 2 seconds delay
});
fetchImage
.then((imageURL) => {
// Display the image on your website
const imageElement = document.createElement('img');
imageElement.src = imageURL;
document.body.appendChild(imageElement);
})
.catch((error) => {
// Handle the error
console.error(error);
});
Introducing Promise.all
In JavaScript Promise.all
is a method that is used for handling asynchronous operations. Promise.all
that takes an array of promises as an input (an iterable) and returns a single Promise. This returned promise will fulfill when all the input promises have fulfilled, or reject immediately if any of the input promises reject.
Syntax and Usage
The syntax for Promise.all is straightforward:
Promise.all(iterable);
Here, the iterable
is an array or any other iterable object containing promises.
Handling Rejections
By default, Promise.all will reject as soon as any of the input promises reject.
Here's a simple example to demonstrate the rejection of Promise.all
in JavaScript:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise 1 resolved');
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('Promise 2 rejected');
}, 1000);
});
Promise.all([promise1, promise2])
.then((results) => {
console.log('All promises resolved:', results);
})
.catch((error) => {
console.log('At least one promise rejected:', error);
});
In the above example, we have two promises: promise1
and promise2
. promise1
resolves after 2 seconds, while promise2
rejects after 1 second. Since promise2
rejects after 1 second the catch
block is executed, and we get the error from the first rejected promise.
Non-Promise Values:
Promise.all() is not limited to Promises only; it can also handle non-Promise values. Any non-Promise values in the input array are immediately resolved:
const promise1 = new Promise((resolve) => setTimeout(resolve, 1000, 'One'))
const promise2 = 'Two'
const promise3 = new Promise((resolve) => setTimeout(resolve, 3000, 'Three'))
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values) // Output: ["One", "Two", "Three"]
})
.catch((error) => {
console.error(error) // This will not be executed in this example
})
Real-World Examples with Code
Fetching multiple user profiles from an API
const userIds = [1, 2, 3]; // Array of user IDs to fetch profiles for
const fetchUserProfile = (userId) => {
return fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json())
.then(profile => {
console.log(`Fetched profile for User ID ${userId}:`, profile);
return profile;
});
};
Promise.all(userIds.map(fetchUserProfile))
.then(profiles => {
console.log('All profiles fetched:', profiles);
// Do something with the fetched profiles
})
.catch(error => {
console.error('Error fetching profiles:', error);
});
Uploading multiple images to a cloud storage service:
const imageFiles = [file1, file2, file3]; // Array of image files to upload
const uploadImage = (file) => {
return new Promise((resolve, reject) => {
const storageRef = firebase.storage().ref();
const imageRef = storageRef.child(`images/${file.name}`);
imageRef.put(file)
.then(snapshot => {
console.log(`Uploaded ${file.name}`);
resolve(snapshot);
})
.catch(error => {
console.error(`Error uploading ${file.name}:`, error);
reject(error);
});
});
};
Promise.all(imageFiles.map(uploadImage))
.then(snapshots => {
console.log('All images uploaded:', snapshots);
// Do something with the uploaded image snapshots
})
.catch(error => {
console.error('Error uploading images:', error);
});
Conclusion
Promise.all([...])
is a useful helper function that lets you to handle asynchronous operations Promise.all([...])
takes an array of promises as an input (an iterable) and returns a single Promise. After reading this article, I hope you feel confident about using Promise.all([...])
. Happy coding!