Promise.all()
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"]
语法
Promise.all(iterable)
参数
返回值
一个 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)。
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)。
// 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 }
解构结果
如果你正在批量处理已知数量的任务,你会发现解构非常有用。
// 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 的异步性或同步性
以下示例演示了当传入非空 iterable 时 Promise.all 的异步性
// 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,也会发生同样的事情
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
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”你的代码。例如,给定以下函数
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();
}
你可能会写出这样的函数
async function getPrice() {
const choice = await promptForDishChoice();
const prices = await fetchPrices();
return prices[choice];
}
然而,请注意 promptForDishChoice 和 fetchPrices 的执行并不相互依赖。当用户选择他们的菜肴时,价格在后台获取是没问题的,但在上面的代码中,await 操作符会导致 async 函数暂停,直到做出选择,然后再次暂停直到价格获取完成。我们可以使用 Promise.all 让它们并发运行,这样用户就不必在给出结果之前等待价格获取完成
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。
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。
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 来改变这种行为
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 |
浏览器兼容性
加载中…