今日的目標:
真實世界不是只有一個 Promise,
很多時候我們會同時發出好幾個非同步任務。
那要怎麼管理呢?
Promise有一些靜態方法可以使用,能幫我們一次處理多個非同步任務。
Promise.all = 全部都要成功,少一個都不行
Promise.all([
fetch("/api/user"),
fetch("/api/posts"),
])
.then(([userRes, postsRes]) => {
if (!userRes.ok) throw new Error("user API 失敗");
if (!postsRes.ok) throw new Error("posts API 失敗");
return Promise.all([userRes.json(), postsRes.json()]);
})
.then(([user, posts]) => {
console.log("user:", user);
console.log("posts:", posts);
})
.catch((err) => {
console.error("其中一個失敗:", err);
});
實務上的用途
Promise.race = 誰先回來,就聽誰的
做「timeout」的例子:
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error("超時")), ms);
});
} //建立一個會在幾秒後失敗的 Promise
Promise.race([
fetch("/api/slow"),
timeout(3000), // 3 秒沒回應就失敗
])
.then((res) => {
if (!res.ok) throw new Error("API 失敗");
return res.json();
})
.then(console.log)
.catch((err) => {
console.error("錯誤或超時:", err.message);
});
實務上的用途
Promise.any = 只要有一個成功就好
Promise.any([
fetch("https://cdn1.example.com/img.png"),
fetch("https://cdn2.example.com/img.png"),
fetch("https://cdn3.example.com/img.png"),
])
.then((res) => {
console.log("至少有一個成功");
return res.blob();
})
.catch((err) => {
console.error("全部都失敗:", err);
});
實務上的用途
Promise.allSettled = 全部完成後,給狀態報表
也就是說,我們想知道每一件是否有成功、哪一件失敗
這時候不是 只要有一個失敗就整包不行,
我們要的是 完整結果。
Promise.allSettled([
fetch("/api/a"),
fetch("/api/b"),
fetch("/api/c"),
])
.then((results) => {
results.forEach((r, i) => {
if (r.status === "fulfilled") {
console.log(`第 ${i} 個成功:`, r.value);
} else {
console.log(`第 ${i} 個失敗:`, r.reason);
}
});
});
實務上的用途
| 方法 | 成功條件 | 失敗條件 | 什麼時候用 |
|---|---|---|---|
| Promise.all | 全部成功 | 任一失敗就失敗 | 所有資料都要到位 |
| Promise.race | 第一個成功就成功 | 第一個失敗就失敗 | timeout、搶最快 |
| Promise.any | 任一成功就成功 | 全部失敗才失敗 | CDN、備援來源 |
| Promise.allSettled | 全部都會回傳結果 | 不會 fail 掉整組 | 統計成功/失敗 |