Watch 10 video solutions for Execute Asynchronous Functions in Parallel, a medium level problem. This walkthrough by Learn With Chirag has 2,306 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
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:
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:
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.
Example 2:
Input: functions = [
() => new Promise(resolve => setTimeout(() => resolve(1), 200)),
() => new Promise((resolve, reject) => setTimeout(() => reject("Error"), 100))
]
Output: {"t": 100, "rejected": "Error"}
Explanation: Since one of the promises rejected, the returned promise also rejected with the same error at the same time.
Example 3:
Input: functions = [
() => new Promise(resolve => setTimeout(() => resolve(4), 50)),
() => new Promise(resolve => setTimeout(() => resolve(10), 150)),
() => new Promise(resolve => setTimeout(() => resolve(16), 100))
]
Output: {"t": 150, "resolved": [4, 10, 16]}
Explanation: All the promises resolved with a value. The returned promise resolved when the last promise resolved.
Constraints:
functions is an array of functions that returns promises1 <= functions.length <= 10Problem Overview: You receive an array of asynchronous functions. Each function returns a promise. Execute all functions in parallel and return a single promise that resolves with their results in the same order. If any promise rejects, the returned promise must reject immediately.
Approach 1: Using Promise Chaining for Resolution (O(n) time, O(n) space)
Create a promise for each async function by calling it immediately so all tasks start in parallel. Use .then() chaining to capture each result and place it at the correct index in a result array. Maintain ordering by storing results based on the original function index rather than completion order. Once all promises resolve, resolve the outer promise with the results array. This mirrors how Promise.all aggregates results internally.
Approach 2: Using Individual Promise Resolution (O(n) time, O(n) space)
Iterate through the array and execute every function immediately so all promises start concurrently. Attach a .then() handler to each promise and store the resolved value in a results array. Track how many promises have completed. When the completion count reaches the number of functions, resolve the main promise with the results array. This approach keeps execution parallel while ensuring ordered output.
Approach 3: Manual Implementation of Promise Handling (O(n) time, O(n) space)
Construct a new promise that internally manages all async calls. For each function, call it and attach both resolve and reject handlers. If any promise rejects, immediately reject the outer promise. Otherwise store the resolved value and continue tracking completions. This approach demonstrates how utilities like Promise.all can be implemented manually using core asynchronous programming and JavaScript promises behavior.
Approach 4: Using a Counter for Resolved Promises (O(n) time, O(n) space)
Initialize a results array and a counter representing how many promises have resolved. Execute each function immediately to ensure parallel execution. When a promise resolves, store the value at its index and increment the counter. Once the counter equals the number of functions, resolve the main promise with the results. This pattern is common in concurrency control when coordinating multiple asynchronous tasks.
Recommended for interviews: The counter-based approach or manual promise handling is usually expected. It proves you understand how parallel asynchronous execution works without relying on built-in helpers like Promise.all. Showing the manual aggregation logic demonstrates strong understanding of promises, ordering guarantees, and failure handling.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Promise Chaining for Resolution | O(n) | O(n) | When you want a clean promise-based aggregation pattern similar to Promise.all |
| Individual Promise Resolution | O(n) | O(n) | When managing each promise independently while preserving order |
| Manual Promise Handling | O(n) | O(n) | When implementing custom behavior similar to Promise.all for interviews |
| Counter for Resolved Promises | O(n) | O(n) | Most common interview pattern for coordinating parallel async tasks |