Skip to content

Promise.all

This lesson explains Promise.all with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.

ES6+ Promise.all Overview

Promise.all() runs multiple Promises in parallel and waits for all of them to fulfill. It returns a single Promise that resolves with an array of results in the same order as the input.

This method is ideal when every async task must succeed before you continue, such as loading all required data for a page, uploading multiple files together, or fetching related resources at once.

Feature Description
Introduced In ES6 (ECMAScript 2015)
Input Iterable of Promises or values
Resolves When All Promises fulfill
Rejects When Any single Promise rejects
Result Order Matches the input order
Common Uses Parallel API calls, batch uploads, data aggregation

Basic Promise.all Example

const p1 = Promise.resolve("User");
const p2 = Promise.resolve("Orders");
const p3 = Promise.resolve("Settings");

Promise.all([p1, p2, p3])
  .then((results) => {
    console.log(results);
  })
  .catch((error) => {
    console.error(error);
  });

When all three Promises fulfill, Promise.all() resolves with ["User", "Orders", "Settings"].

How Promise.all Works

Promise.all() starts every Promise at the same time. It does not wait for one to finish before starting the next.

Step Description Example
Pass Iterable Provide an array of Promises. [p1, p2, p3]
Run in Parallel All Promises start immediately. Concurrent requests
Collect Results Store fulfilled values in order. [value1, value2]
Resolve Together Return when all succeed. results
Fail Fast Reject immediately on first failure. .catch(...)

Parallel Fetch Requests

Promise.all([
  fetch("/api/user"),
  fetch("/api/orders"),
  fetch("/api/settings")
])
  .then((responses) =>
    Promise.all(
      responses.map((res) => res.json())
    )
  )
  .then(([user, orders, settings]) => {
    console.log(user);
    console.log(orders);
    console.log(settings);
  })
  .catch((error) => {
    console.error(
      "One request failed:",
      error
    );
  });

This is one of the most common real-world uses of Promise.all(). Multiple API calls run at the same time instead of one after another.

Fail-Fast Error Handling

const tasks = [
  Promise.resolve("Step 1 done"),
  Promise.reject(
    new Error("Step 2 failed")
  ),
  Promise.resolve("Step 3 done")
];

Promise.all(tasks)
  .then((results) => {
    console.log(results);
  })
  .catch((error) => {
    console.error(error.message);
  });

If any Promise rejects, Promise.all() rejects immediately with that error. The remaining successful results are not returned.

Promise.all with Array.map

const userIds = [1, 2, 3, 4];

const requests = userIds.map((id) =>
  fetch(
    `https://jsonplaceholder.typicode.com/users/${id}`
  ).then((res) => res.json())
);

Promise.all(requests)
  .then((users) => {
    console.log(
      users.map((user) => user.name)
    );
  })
  .catch((error) => {
    console.error(error);
  });

Mapping over an array to create Promises and passing them to Promise.all() is a clean pattern for batch requests.

Promise.all with async/await

async function loadDashboard() {
  try {
    const [userRes, statsRes] =
      await Promise.all([
        fetch("/api/user"),
        fetch("/api/stats")
      ]);

    const user =
      await userRes.json();
    const stats =
      await statsRes.json();

    return { user, stats };
  } catch (error) {
    console.error(
      "Dashboard load failed",
      error
    );
    throw error;
  }
}

loadDashboard()
  .then((data) => console.log(data));

async/await makes Promise.all() results easy to destructure into named variables for cleaner application code.

Non-Promise Values in Promise.all

Promise.all([
  Promise.resolve("Async value"),
  42,
  "plain string"
])
  .then((results) => {
    console.log(results);
  });

Non-Promise values are treated as already fulfilled. This means you can mix Promises and plain values in the same array.

Empty Array Behavior

Promise.all([])
  .then((results) => {
    console.log(results);
    console.log(results.length);
  });

Passing an empty array to Promise.all() resolves immediately with an empty array. This is useful for dynamic lists that may sometimes contain zero tasks.

Sequential vs Parallel Execution

// Sequential: slower

async function loadSequential() {
  const user =
    await fetch("/api/user");
  const orders =
    await fetch("/api/orders");
  return [user, orders];
}

// Parallel: faster

async function loadParallel() {
  const [user, orders] =
    await Promise.all([
      fetch("/api/user"),
      fetch("/api/orders")
    ]);
  return [user, orders];
}

Use Promise.all() when tasks are independent and can run at the same time. Use sequential await when one task depends on the result of another.

Promise.all vs Other Combinators

Method Resolves When Rejects When Best For
Promise.all() All Promises fulfill Any Promise rejects All tasks must succeed
Promise.allSettled() All Promises settle Never rejects Partial success reporting
Promise.race() First Promise settles First Promise rejects First finished result
Promise.any() First Promise fulfills All Promises reject First successful result

Common Promise.all Use Cases

  • Loading multiple API endpoints for a single page.
  • Uploading several files at the same time.
  • Fetching user data from multiple microservices.
  • Running independent validation checks in parallel.
  • Preloading assets before rendering a view.
  • Batch database or cache lookups.
  • Waiting for all setup tasks before app initialization.

Promise.all Best Practices

  • Use Promise.all() only when every task must succeed.
  • Prefer parallel requests for independent async work.
  • Always handle rejection with .catch() or try/catch.
  • Destructure results with meaningful variable names.
  • Use Promise.allSettled() when partial failure is acceptable.
  • Avoid unnecessary Promise wrappers around synchronous values.
  • Consider timeouts or retries for unreliable network requests.

Common Promise.all Mistakes

  • Using Promise.all() when only some results are required.
  • Assuming tasks run sequentially instead of in parallel.
  • Forgetting that one failure rejects the entire batch.
  • Not handling errors from any individual Promise.
  • Using Promise.all() for dependent sequential workflows.
  • Expecting result order to match completion time instead of input order.
  • Passing an array of unresolved fetch calls without parsing responses.

Key Takeaways

  • Promise.all() runs multiple Promises in parallel.
  • It resolves with an array of results in input order.
  • It rejects immediately if any Promise fails.
  • It is best for workflows where every task must succeed.
  • Pair it with async/await for clean, readable code.

Pro Tip

If a page needs user, orders, and settings data and all three are required to render, Promise.all() is the right choice. If one section can fail independently, use Promise.allSettled() instead.