Practice Promise.all and Promise.race

Asynchronous Processing in JavaScript

Asynchronous processing is a cornerstone of JavaScript, enabling efficient handling of tasks that cannot be completed synchronously. Two key constructs, Promise.all() and Promise.race(), are essential for managing multiple asynchronous operations. This article explores their usage, differences, and practical applications.

Promise.all()

Promise.all() resolves to an array of values when all specified promises resolve, or rejects immediately if any promise fails. It is ideal for scenarios where multiple asynchronous tasks need to be executed concurrently.

Usage Example

const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
  .then(values => {
    console.log(values); // [1, 2, 3]
  })
  .catch(error => {
    console.error("One or more promises failed:", error);
  });

Key Features

  • Concurrent Execution: All promises are processed simultaneously.
  • Error Handling: If any promise fails, the entire Promise.all() rejects.
  • Array Aggregation: Results are collected into an array.

Use Cases

  • Parallel API calls to reduce latency.
  • Batch processing of multiple tasks.

Promise.race()

Promise.race() resolves based on the first promise to resolve or reject. It is useful for checking the status of multiple asynchronous operations quickly.

Usage Example

const promise1 = Promise.resolve("Result from Promise 1");
const promise2 = Promise.reject("Error from Promise 2");

Promise.race([promise1, promise2])
  .then(result => {
    console.log(result); // "Result from Promise 1"
  })
  .catch(error => {
    console.error(error); // "Error from Promise 2"
  });

Key Features

  • First to Resolve/Reject: The first promise in the array determines the outcome.
  • Simplified Logic: Requires fewer lines of code compared to Promise.all().

Use Cases

  • Quick checks for the status of multiple requests.
  • Handling timeouts or early termination of long-running tasks.

Differences and When to Use

Feature Promise.all() Promise.race()
Resolution Resolves only if all promises resolve Resolves based on the first promise
Error Handling Rejects if any promise fails Rejects if the first promise fails
Performance Efficient for large numbers of promises Efficient for checking early outcomes
Use Case Parallel processing of multiple tasks Quick status checks for multiple tasks

When to Choose Each

  • Use Promise.all() when all promises must succeed, such as processing a batch of data.
  • Use Promise.race() when you need to know the status of multiple tasks quickly, like checking if a user is logged in.

Practical Examples

Scenario 1: Parallel API Calls

const api1 = fetch("https://api.example.com/data1");
const api2 = fetch("https://api.example.com/data2");

Promise.all([api1, api2])
  .then(response => {
    console.log("All requests completed:", response);
  })
  .catch(error => {
    console.error("One or both requests failed:", error);
  });

Scenario 2: Early Termination

const timeout = setTimeout(() => {
  console.log("Timeout triggered");
}, 1000);

Promise.race([fetchData(), timeout])
  .then(data => {
    console.log("Data received:", data);
  })
  .catch(error => {
    console.error("Request failed:", error);
  });

Conclusion

Promise.all() and Promise.race() are critical tools for managing asynchronous operations in JavaScript. While Promise.all() ensures all promises succeed, Promise.race() provides efficient, early feedback. Understanding their differences and use cases allows developers to build robust, responsive applications. By leveraging these constructs, asynchronous processing becomes both scalable and manageable.