Promise.all()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

Promise.all() 静态方法接受一个 promises 的可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 promises 都 fulfilled 时(包括传入空可迭代对象时),这个返回的 promise 也会 fulfilled,并带有一个包含所有 fulfillment 值的数组。如果输入的 promises 中有任何一个 rejected,它就会 rejected,并带上第一个 rejection 的原因。

试一试

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "foo");
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// Expected output: Array [3, 42, "foo"]

语法

js
Promise.all(iterable)

参数

iterable

一个 promise 的 可迭代对象(例如 Array)。

返回值

一个 Promise,它

  • 如果传入的 iterable 为空,则已 fulfilled
  • 当给定 iterable 中的所有 promises 都 fulfilled 时,则异步 fulfilled。fulfillment 值是一个 fulfillment 值的数组,顺序与传入 promises 的顺序相同,与完成顺序无关。如果传入的 iterable 非空但没有待定的 promises,返回的 promise 仍然会异步(而不是同步)fulfilled。
  • 当给定 iterable 中的任何 promise rejected 时,则异步 rejected。rejection 的原因是第一个被 rejected 的 promise 的 rejection 原因。

描述

Promise.all() 方法是 promise 并发方法之一。它对于聚合多个 promises 的结果非常有用。它通常用于当有多个相关的异步任务,且整体代码需要依赖所有任务成功完成才能继续执行的情况——我们希望所有这些任务都在代码继续执行之前 fulfilled。

Promise.all() 会在输入 promises 中有任何一个 rejected 时立即 rejected。相比之下,Promise.allSettled() 返回的 promise 会等待所有输入 promises 完成,无论是否有 rejected。如果你需要输入可迭代对象中每个 promise 的最终结果,请使用 allSettled()

示例

使用 Promise.all()

Promise.all 等待所有 fulfillment(或第一个 rejection)。

js
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 100);
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [3, 1337, "foo"]
});

如果 iterable 包含非 promise 值,它们将被忽略,但仍然计入返回的 promise 数组值中(如果 promise fulfilled)。

js
// All values are non-promises, so the returned promise gets fulfilled
const p = Promise.all([1, 2, 3]);
// The only input promise is already fulfilled,
// so the returned promise gets fulfilled
const p2 = Promise.all([1, 2, 3, Promise.resolve(444)]);
// One (and the only) input promise is rejected,
// so the returned promise gets rejected
const p3 = Promise.all([1, 2, 3, Promise.reject(new Error("bad"))]);

// Using setTimeout, we can execute code after the queue is empty
setTimeout(() => {
  console.log(p);
  console.log(p2);
  console.log(p3);
});

// Logs:
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: Error: bad }

解构结果

如果你正在批量处理已知数量的任务,你会发现解构非常有用。

js
// With then()
Promise.all([p1, p2, p3]).then(([a, b, c]) => {
  console.log(a, b, c); // 3 1337 "foo"
});

// With await
const [a, b, c] = await Promise.all([p1, p2, p3]);

请注意:如果原始 promises 和结果变量的顺序不匹配,你可能会遇到微妙的 bug。

Promise.all 的异步性或同步性

以下示例演示了当传入非空 iterablePromise.all 的异步性

js
// Passing an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

const p = Promise.all(resolvedPromisesArray);
// Immediately logging the value of p
console.log(p);

// Using setTimeout, we can execute code after the queue is empty
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p);
});

// Logs, in order:
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

如果 Promise.all rejected,也会发生同样的事情

js
const mixedPromisesArray = [
  Promise.resolve(33),
  Promise.reject(new Error("bad")),
];
const p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p);
});

// Logs:
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "rejected", <reason>: Error: bad }

Promise.all 仅当传入的 iterable 为空时才会同步 resolve

js
const p = Promise.all([]); // Will be immediately resolved
const p2 = Promise.all([1337, "hi"]); // Non-promise values are ignored, but the evaluation is done asynchronously
console.log(p);
console.log(p2);
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p2);
});

// Logs:
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

将 Promise.all() 与 async 函数一起使用

async 函数中,非常常见地会“过度 await”你的代码。例如,给定以下函数

js
function promptForDishChoice() {
  return new Promise((resolve, reject) => {
    const dialog = document.createElement("dialog");
    dialog.innerHTML = `
<form method="dialog">
  <p>What would you like to eat?</p>
  <select>
    <option value="pizza">Pizza</option>
    <option value="pasta">Pasta</option>
    <option value="salad">Salad</option>
  </select>
  <menu>
    <li><button value="cancel">Cancel</button></li>
    <li><button type="submit" value="ok">OK</button></li>
  </menu>
</form>
    `;
    dialog.addEventListener("close", () => {
      if (dialog.returnValue === "ok") {
        resolve(dialog.querySelector("select").value);
      } else {
        reject(new Error("User cancelled dialog"));
      }
    });
    document.body.appendChild(dialog);
    dialog.showModal();
  });
}

async function fetchPrices() {
  const response = await fetch("/prices");
  return await response.json();
}

你可能会写出这样的函数

js
async function getPrice() {
  const choice = await promptForDishChoice();
  const prices = await fetchPrices();
  return prices[choice];
}

然而,请注意 promptForDishChoicefetchPrices 的执行并不相互依赖。当用户选择他们的菜肴时,价格在后台获取是没问题的,但在上面的代码中,await 操作符会导致 async 函数暂停,直到做出选择,然后再次暂停直到价格获取完成。我们可以使用 Promise.all 让它们并发运行,这样用户就不必在给出结果之前等待价格获取完成

js
async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice(),
    fetchPrices(),
  ]);
  return prices[choice];
}

Promise.all 是这里并发方法的最佳选择,因为错误处理很直观——如果任何 promises rejected,结果将不再可用,因此整个 await 表达式都会抛出错误。

Promise.all 接受一个 promises 的可迭代对象,因此如果你使用它来并发运行多个 async 函数,你需要调用 async 函数并使用返回的 promises。直接将函数传递给 Promise.all 不起作用,因为它们不是 promises。

js
async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice,
    fetchPrices,
  ]);
  // `choice` and `prices` are still the original async functions;
  // Promise.all() does nothing to non-promises
}

Promise.all 快速失败行为

如果任何元素被 rejected,Promise.all 就会被 rejected。例如,如果你传入四个在超时后 resolve 的 promises 和一个立即 rejected 的 promise,那么 Promise.all 将立即 rejected。

js
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("one"), 1000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("two"), 2000);
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("three"), 3000);
});
const p4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("four"), 4000);
});
const p5 = new Promise((resolve, reject) => {
  reject(new Error("reject"));
});

// Using .catch:
Promise.all([p1, p2, p3, p4, p5])
  .then((values) => {
    console.log(values);
  })
  .catch((error) => {
    console.error(error.message);
  });

// Logs:
// "reject"

可以通过处理可能的 rejection 来改变这种行为

js
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("p1_delayed_resolution"), 1000);
});

const p2 = new Promise((resolve, reject) => {
  reject(new Error("p2_immediate_rejection"));
});

Promise.all([p1.catch((error) => error), p2.catch((error) => error)]).then(
  (values) => {
    console.log(values[0]); // "p1_delayed_resolution"
    console.error(values[1]); // "Error: p2_immediate_rejection"
  },
);

规范

规范
ECMAScript® 2026 语言规范
# sec-promise.all

浏览器兼容性

另见