Parallel Task Execution with Async/Await
This challenge focuses on implementing a function that executes an array of asynchronous tasks in parallel, collecting their results in a specific order. Parallel execution is crucial for optimizing performance in scenarios where tasks are independent and waiting for one to complete before starting the next would be inefficient. This problem tests your understanding of async/await, Promises, and managing asynchronous operations effectively.
Problem Description
You are tasked with creating a JavaScript function called parallelExecute that accepts an array of asynchronous functions (Promises) as input. Each function in the array should return a Promise that resolves to a value. The parallelExecute function should execute all these functions concurrently (in parallel) and return a new Promise that resolves to an array containing the results of each function, in the same order as the input array.
Key Requirements:
- Parallel Execution: The functions in the input array must be executed concurrently. Avoid sequential execution.
- Order Preservation: The resolved values in the output array must maintain the same order as the functions in the input array.
- Error Handling: If any of the asynchronous functions reject (throw an error), the
parallelExecutefunction should reject with the error from the first rejected Promise. Subsequent rejections should be ignored. - Promise-Based: The function must return a Promise.
Expected Behavior:
The parallelExecute function should:
- Take an array of asynchronous functions (Promises) as input.
- Execute all functions concurrently.
- Collect the resolved values from each function.
- Return a Promise that resolves to an array containing the collected values in the original order.
- If any function rejects, the returned Promise should reject with the error from the first rejected function.
Edge Cases to Consider:
- Empty Input Array: If the input array is empty, the function should resolve with an empty array immediately.
- Functions that resolve immediately: Handle functions that resolve very quickly without blocking.
- Functions that reject immediately: Handle functions that reject very quickly.
- Mixed Resolutions and Rejections: Handle scenarios where some functions resolve and others reject.
Examples
Example 1:
Input: [
() => new Promise(resolve => setTimeout(() => resolve('Task 1'), 100)),
() => new Promise(resolve => setTimeout(() => resolve('Task 2'), 200)),
() => new Promise(resolve => setTimeout(() => resolve('Task 3'), 50))
]
Output: ['Task 1', 'Task 2', 'Task 3']
Explanation: All three tasks are executed concurrently. 'Task 3' resolves first (50ms), then 'Task 1' (100ms), and finally 'Task 2' (200ms). The output array preserves the original order.
Example 2:
Input: [
() => new Promise(resolve => setTimeout(() => resolve('Task 1'), 100)),
() => new Promise((resolve, reject) => setTimeout(() => reject('Task 2 Error'), 200)),
() => new Promise(resolve => setTimeout(() => resolve('Task 3'), 50))
]
Output: Rejects with 'Task 2 Error'
Explanation: 'Task 2' rejects after 200ms. The `parallelExecute` function immediately rejects with the error from 'Task 2', and the other tasks are effectively cancelled (though they may still execute in the background).
Example 3:
Input: []
Output: []
Explanation: The input array is empty. The function resolves immediately with an empty array.
Constraints
- The input array will contain only functions that return Promises.
- The maximum number of functions in the input array is 100.
- The resolution/rejection time of each asynchronous function is expected to be between 0ms and 1 second.
- The function should complete execution within 2 seconds, even in cases of errors or long-running tasks.
Notes
Consider using Promise.all() or Promise.allSettled() as a starting point, but ensure you correctly handle error propagation and order preservation. Think about how to manage the asynchronous nature of the tasks and ensure that the results are collected in the correct sequence. The key is to execute the tasks concurrently while maintaining the original order of the results.