Promise.all
Let’s say we want many promises to execute in parallel and wait until all of them are resolved. Then Promise.all is the right candidate which takes an array of promises and returns a new promise.
Let's understand how Promise.all
works.
Promise Resolves when:
- Promises which will be fulfilled after sometime (Eg: API which fulfills after 10 seconds)
- Promises that have been already fulfilled (Eg: API which fulfils before passing to .all())
- Non-promises based functions, variables etc, (Eg: Function which returns a value)
Promise Rejects when:
- If one of promise get rejected, then
Promise.all
immediately rejects, completely ignoring about the other ones on the list.
We are going to see an example of Promise.all
and then we will implement it.
Example:
/* A simple function to sleep for certain time and then resolve it */
var sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
// Async function
var asyncFunz = async () => {
await sleep(2000); // await method will wait for 2 seconds and return below string
return 'Executed after 2 seconds';
};
/* Fetch user information */
var promise2 = fetch(`https://reqres.in/api/user/1`).then((res) => res.json());
/* A simple function which add's two numbers and return it */
var sum = (a, b) => a + b;
/* Adding above methods and some more to Promise.all method */
var myPromises = Promise.all([asyncFunz(), promise2, sum(1, 2), undefined, null, 1]);
/* Attaching .then, .catch methods to handle Promise.all */
myPromises.then((res) => console.log('resolved: ', res)).catch((err) => console.log('rejected: ', err));
// Above Promise.all resolves and log the result (Below line for result)
// resolved: ["Executed after 2 seconds", {data: {...}}, 3, undefined, null, 1]
In the above example, asyncFunz, promise2 are actual async functions and the rest of items in the array are a normal Function
, Undefined
, Null
and 1
.
From above example we can understand that Promise.all
method accepts both async
and non-async
items, functions, variables etc,.
To write our custom promise.all(), we are going follow 3 steps.
Step 1:
- Create a function called promiseAll which accepts a parameter called
promisesArr
. - This function will have two variables: result (Type:
Array
) & counter (Type:Number
). result
variable is to store the result of items inpromisesArr
.counter
variable to keep the count of how many items resolved so far inpromisesArr
.- Finally, add
Promise
object toresolve/reject
and return it (More info on step 2
).
/* Promise.all() custom function */
function promiseAll(promisesArr) {
/* To keep the result of resolved promises */
var result = Array(promisesArr.length);
/* To keep track of how many promise got resolved */
var counter = 0;
/* To resolve/reject based on promisesArr items */
return new Promise((resolve, reject) => {});
}
Step 2:
- Iterate the given promisesArr inside
new Promise()
object so we can either catch or resolve the items at each iteration. - Each item from promisesArr is passed to
Promise.resolve()
method to handle both promise & non-promise items. - Add
.then()
&.catch()
chaining methods toPromise.resolve()
method to handle when the itemssettles
in each iteration.
function promiseAll(promisesArr) {
/* To keep the result of resolved promises */
var result = Array(promisesArr.length);
/* To keep track of how many promise got resolved */
var counter = 0;
/* To resolve/reject based on promisesArr items */
return new Promise((resolve, reject) => {
// Iterating the given promises array
promisesArr.forEach((promise, index) => {
// To handle both promise & non-promise in each iteration
Promise.resolve(promise)
.then((item) => {
// Store the result
})
.catch((err) => {
// If there is an error, reject it immediately
});
});
});
}
Final Step:
- When the
Promise.resolve()
resolves, increment the counter. - Store the resolved item in
result
variable in the respective index. So that we can maintain the order of result. - If the
counter
is equal to promisesArr's length, then resolve the promise. - If even one item in
promiseArr
is rejected, then discard result and reject the outer promise.
function promiseAll(promisesArr) {
/* To keep the result of resolved promises */
var result = Array(promisesArr.length);
/* To keep track of how many promise got resolved */
var counter = 0;
/* To resolve/reject based on promisesArr items */
return new Promise((resolve, reject) => {
// Iterating the given promises array
promisesArr.forEach((promise, index) => {
// We need to resolve each item in promises so that even if there is non-promise item we can handle it
Promise.resolve(promise)
.then((item) => {
counter += 1; // Update the counter
result[index] = item; // Store the result in the same order as given
/* If counter is equal to promises.length then all promises are fulfilled */
if (counter === promisesArr.length) {
resolve(result); // All promises resolved so resolve outer promise
}
})
.catch((err) => {
reject(err); // If there is an error, reject the outer promise immediately
});
});
});
}
Wrapping up
Above piece of code may not be same as how browser vendors would have implemented Promise.all()
method, but you get the idea right how it works?.
I hope this post was useful and we all have learned something new. See you in my next post. My next post will be about how to write custom spread operator
and how it works. If you are not subscribed, subscribe below :D