Parallel promise execution: Beyound Promise.all()
abdellah ht
Posted on March 31, 2022
In this post, I will talk about running promises in parallel and optimizing for the lowest waiting time possible.
When you have a bunch of promises that need to execute sequentially, you
just run them in a sequence usein .then()
or awaits
:
getUser()
.then((user) => getPosts(user.id))
.then((posts) => use(posts));
// Or
let user = await getUser();
let posts = await getPosts(user.id);
use(posts);
But when they don't depend on each other like the posts
that need the user id
,
you can run them in parallel using Promise.all()
.
let [value1, value2, valueN] = await Promise.all([promise1, promise2, promiseN]);
Which accepts an array of an arbitrary number of promises and returns a promise with all the valuse
once each of them is resolved.
If one of them fails, the whole things rejects
with the first error that occured.
One possible solution to prevent the whole thing from failing would be to chain the promiseN
in
the array with a .catch()
which will make it always resolve no matter. The problem that arrises
is how to detect if the valueN
we get on the other side is from its resolution or rejection.
A possible solution would be to always return a tuple or an object from these promises.
Example:
const wrap = (promise) => promise.then((value) => ({ error: null, value })).catch((error) => ({ error }));
With this utility in hand, we can inspect the valueN
on the other side to see if it was a success or not,
and there's still room for sophisticaiton to return more metadata for retrying purposes.
const wrappedPromises = [promise1, promise2, promiseN].map((promise) => wrap(promise));
let values = await Promise.all(wrappedPromises);
What about when the array of promises is huge (by whatever definition makes sense for your application),
maybe you're running some resource intensive processes and don't want to exceed 10 at a time?
The answer is chunking, you could use something like lodash.chunk
or roll your own.
let chunks = _.chunk(arrayOfPromises, 10);
for (let chunk of chunks) {
let chunkValues = await Promise.all(chunk.map(wrap));
use(chunkValues);
}
This was part of a recent optimization job I did for a client, I hope you found it as helpful as I did.
If you enjoyed this post, don't forget like and follow for more.
:wq
Posted on March 31, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 23, 2024
August 25, 2024