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

瀏覽器相容性

另見