DEV Community

druchan
druchan

Posted on

Parallel promises made simple - Javascript Tip

Promise.all and Promise.allSettled have made it easy to run promises parallelly. However, the data returned by Promise.allSettled (which is what I often end up having to use because Promise.all fails at the first promise that rejects/fails) is slightly cumbersome to deal with.

Instead, I use a recipe where it becomes easy for me to run parallel promise functions and handle the data far more easily.

Before I show the recipe, here's how the usage looks like:

// let's say we have these functions that return a promise
const getUsers = () => axios.get('/users');
const getTeams = () => axios.get('/teams');
const getPlans = () => axios.get('/plans');
const setConfig = () => axios.post('/config', { data: config }); // config comes from somewhere

// now, we have to run these on app-load
const results = await runPromises({
  users: getUsers,
  teams: getTeams,
  plans: getPlans,
  config: setConfig,
});
// runPromises is the recipe.

// and then `results` will look like this:
// results == {
//   users: { data: [...] }, // or { error: AxiosError }
//   teams: { data: [...] }, // or { error: AxiosError }
//   plans: { data: [...] }, // or { error: AxiosError }
//   config: { data: {...} }, // or { error: AxiosError }
// }
Enter fullscreen mode Exit fullscreen mode

The object-based approach is not as great as a list but you can see the benefit - no need to deal with status and value and reason for each. Instead, each key in your object (which maps to a function) will have a resolved value object that either contains the data key or the error key.

Here's the recipe to use:

const runPromises = async (promises) => {
  let plist = Object.entries(promises).map(async ([name, promise]) => {
    let res;
    try {
      res = { data: await promise() };
    } catch (e) {
      res = { error: e };
    }
    return [name, res];
  });
  let intermediateResult = [];
  for (let p of plist) {
    await intermediateResult.push(await p);
  }
  return Object.fromEntries(intermediateResult);
};
Enter fullscreen mode Exit fullscreen mode

Briefly, what we do is convert the object into a [key, value] pair list, then run each promise (but because this is a map, it is run parallelly), and finally collect these promises into another [key, value] pair list and return that as an object.

Top comments (0)