Implementing N Async Tasks in Parallel in JavaScript



Implementing N asynchronous tasks in parallel means running multiple tasks simultaneously and waiting for all of them to complete. This approach is beneficial for improving performance when tasks are independent of each other.


What is Parallel Execution?

Parallel execution involves running multiple tasks at the same time. Each task runs independently, and the overall execution time is determined by the task that takes the longest to complete.

Real Interview Insights

Interviewers might ask you to:

  • Implement a function to execute an array of asynchronous tasks in parallel.
  • Ensure all tasks are initiated at the same time.
  • Handle results and errors appropriately.

Implementing runTasksInParallel Function

Here’s an implementation of a function to run N async tasks in parallel:

function runTasksInParallel(tasks) {
  return Promise.all(tasks.map(task => task()));
}
Explanation:
  • Mapping Tasks: Use Array.prototype.map to create an array of task promises.
  • Promise.all: Use Promise.all to run all the promises in parallel and wait for all of them to resolve.

Practical Examples

Consider an example with async tasks:

const tasks = [
  () => new Promise(resolve => setTimeout(() => resolve('Task 1'), 1000)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 2'), 500)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 3'), 300))
];
 
runTasksInParallel(tasks).then(results => {
  console.log(results); // Output: ['Task 1', 'Task 2', 'Task 3']
});

Handling Edge Cases

  1. Empty Task Array: Handle cases where the array of tasks is empty.
  2. Error Handling: Ensure that errors in any task are properly caught and handled.

Enhanced Implementation with Error Handling

function runTasksInParallel(tasks) {
  return Promise.all(
    tasks.map(task =>
      task().catch(error => {
        console.error(`Error in task: ${error.message}`);
        return null; // Or handle the error as needed
      })
    )
  );
}
 
// Example usage with error handling
const tasks = [
  () => new Promise(resolve => setTimeout(() => resolve('Task 1'), 1000)),
  () => new Promise((resolve, reject) => setTimeout(() => reject(new Error('Task 2 failed')), 500)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 3'), 300))
];
 
runTasksInParallel(tasks).then(results => {
  console.log(results); // Output: ['Task 1', null, 'Task 3']
});

Use Cases for Parallel Execution

  1. Independent Tasks: When tasks do not depend on each other.
  2. Performance Optimization: Reduce overall execution time by running tasks simultaneously.
  3. Batch Processing: Handle multiple requests or operations concurrently.