[Medium] LeetCode JS 30 - 2721. Execute Asynchronous Functions in Parallel

March 6, 2024

☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee

LeetCode 30 Days of JavaScript

This question is from LeetCode's 30 Days of JavaScript Challenge

2721. Execute Asynchronous Functions in Parallel

Question Prompt

Given an array of asynchronous functions functions, return a new promise promise. Each function in the array accepts no arguments and returns a promise. All the promises should be executed in parallel.

promise resolves:

  • When all the promises returned from functions were resolved successfully in parallel. The resolved value of promise should be an array of all the resolved values of promises in the same order as they were in the functions. The promise should resolve when all the asynchronous functions in the array have completed execution in parallel.

promise rejects:

  • When any of the promises returned from functions were rejected. promise should also reject with the reason of the first rejection.

Please solve it without using the built-in Promise.all function.

// Example 1:
Input: functions = [
  () => new Promise(resolve => setTimeout(() => resolve(5), 200))
]
Output: {"t": 200, "resolved": [5]}
Explanation:
promiseAll(functions).then(console.log); // [5]

The single function was resolved at 200ms with a value of 5.

Solutions

Looking to practice more questions like these? We recommend GreatFrontEnd, the best platform for honing your frontend interview skills!

First, we can check if the input array, promises, is empty, it means there are no promises to coordinate. We directly resolve with an empty array using Promise.resolve([]).

Then, we create an output array called outputs to store the results of our promises. It's the same size as the input array to maintain the correct order. Also, we create resolveCounter to track how many promises have successfully resolved.

For the core, we construct a new Promise. This is important as our promiseAll function itself returns a promise that the caller can depend on. We use forEach, we go through each promise in the input.

With .then, we handle what happens when a promise resolves. We store the resolved value in its corresponding position in the outputs array. We increase resolveCounter.

If resolveCounter matches the total number of promises, it means all the promises have been resolved, so we resolve the primary promise.

For error handling, we use .catch to take care of it. if any promise rejects, we immediately reject the primary promise

var promiseAll = function (promises) {
  // Base case: If there are no promises, immediately resolve with an empty array
  if (promises.length === 0) {
    return Promise.resolve([]);
  }

  // Create an array to hold the results of each promise
  const outputs = new Array(promises.length);
  // Counter to track how many promises have resolved successfully
  let resolveCounter = 0;

  return new Promise((resolve, reject) => {
    // Iterate over each promise in the input array
    promises.forEach((promise, index) => {
      // Invoke the promise immediately
      promise()
        .then((value) => {
          // Store the resolved value in the corresponding index of the outputs array
          outputs[index] = value;
          // Increment the counter of resolved promises
          resolveCounter += 1;

          // If all promises have resolved, resolve the main promise with the outputs array
          if (resolveCounter === promises.length) {
            resolve(outputs);
          }
        })
        .catch((err) => {
          // If any promise rejects, reject the main promise with the error
          reject(err);
        });
    });
  });
};

Code without comments

var promiseAll = function (promises) {
  if (promises.length === 0) {
    return Promise.resolve([]);
  }

  const outputs = new Array(promises.length);
  let resolveCounter = 0;

  return new Promise((resolve, reject) => {
    promises.forEach((promise, index) => {
      promise()
        .then((value) => {
          outputs[index] = value;
          resolveCounter += 1;
          if (resolveCounter === promises.length) {
            resolve(outputs);
          }
        })
        .catch(reject);
    });
  });
};
☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee