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 using .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 values once each of them is resolved.

If one of them fails, the whole things rejects with the first error that occurred.

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 sophistication 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