Promise.race()
Promise.race() 靜態方法接收一個 promise 可迭代物件作為輸入,並返回一個單獨的 Promise。這個返回的 promise 會以第一個 settled(已完成或已拒絕)的 promise 的狀態來 settled。
試一試
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "one");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "two");
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// Expected output: "two"
語法
Promise.race(iterable)
引數
返回值
一個 Promise,它會 **非同步 settled**,狀態與 iterable 中第一個 settled 的 promise 相同。換句話說,如果第一個 settled 的 promise 是 fulfilled(成功),則返回的 promise 也 fulfilled;如果第一個 settled 的 promise 是 rejected(失敗),則返回的 promise 也 rejected。如果傳入的 iterable 為空,則返回的 promise 將永遠處於 pending(等待)狀態。如果傳入的 iterable 非空但其中不包含任何 pending 的 promise,則返回的 promise 仍會 **非同步**(而不是同步)settled。
描述
Promise.race() 方法是 Promise 併發 方法之一。當你只需要關心第一個完成的非同步任務,而不在乎它的最終狀態(即它可以成功也可以失敗)時,它非常有用。
如果可迭代物件包含一個或多個非 promise 值和/或一個已 settled 的 promise,那麼 Promise.race() 將會以可迭代物件中找到的第一個此類值來 settled。
示例
使用 Promise.race()
此示例展示瞭如何使用 Promise.race() 來競速幾個使用 setTimeout() 實現的定時器。時間最短的定時器將贏得比賽,併成為結果 promise 的狀態。
function sleep(time, value, state) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (state === "fulfill") {
resolve(value);
} else {
reject(new Error(value));
}
}, time);
});
}
const p1 = sleep(500, "one", "fulfill");
const p2 = sleep(100, "two", "fulfill");
Promise.race([p1, p2]).then((value) => {
console.log(value); // "two"
// Both fulfill, but p2 is faster
});
const p3 = sleep(100, "three", "fulfill");
const p4 = sleep(500, "four", "reject");
Promise.race([p3, p4]).then(
(value) => {
console.log(value); // "three"
// p3 is faster, so it fulfills
},
(error) => {
// Not called
},
);
const p5 = sleep(500, "five", "fulfill");
const p6 = sleep(100, "six", "reject");
Promise.race([p5, p6]).then(
(value) => {
// Not called
},
(error) => {
console.error(error.message); // "six"
// p6 is faster, so it rejects
},
);
Promise.race 的非同步性
以下示例演示了 Promise.race 的非同步性。與其他 Promise 併發方法不同,Promise.race 始終是非同步的:它永遠不會同步 settled,即使 iterable 為空。
// Passing an array of promises that are already resolved,
// to trigger Promise.race as soon as possible
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];
const p = Promise.race(resolvedPromisesArray);
// Immediately logging the value of p
console.log(p);
// Using setTimeout, we can execute code after the stack is empty
setTimeout(() => {
console.log("the stack is now empty");
console.log(p);
});
// Logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: 33 }
空的可迭代物件會導致返回的 promise 永遠處於 pending 狀態
const foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(() => {
console.log("the stack is now empty");
console.log(foreverPendingPromise);
});
// Logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "pending" }
如果可迭代物件包含一個或多個非 promise 值和/或一個已 settled 的 promise,那麼 Promise.race 將會以在陣列中找到的第一個此類值來 settled。
const foreverPendingPromise = Promise.race([]);
const alreadyFulfilledProm = Promise.resolve(100);
const arr = [foreverPendingPromise, alreadyFulfilledProm, "non-Promise value"];
const arr2 = [foreverPendingPromise, "non-Promise value", Promise.resolve(100)];
const p = Promise.race(arr);
const p2 = Promise.race(arr2);
console.log(p);
console.log(p2);
setTimeout(() => {
console.log("the stack is now empty");
console.log(p);
console.log(p2);
});
// Logs, in order:
// Promise { <state>: "pending" }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: 100 }
// Promise { <state>: "fulfilled", <value>: "non-Promise value" }
使用 Promise.race() 實現請求超時
你可以將一個可能耗時很長的請求與一個會 rejection 的定時器進行競速,這樣當時間限制過去後,結果 promise 就會自動 rejection。
const data = Promise.race([
fetch("/api"),
new Promise((resolve, reject) => {
// Reject after 5 seconds
setTimeout(() => reject(new Error("Request timed out")), 5000);
}),
])
.then((res) => res.json())
.catch((err) => displayError(err));
如果 data promise fulfilled,它將包含從 /api 獲取的資料;否則,如果 fetch 保持 pending 5 秒並輸給了 setTimeout 定時器,它將 rejection。
使用 Promise.race() 檢測 promise 的狀態
由於 Promise.race() 解析為可迭代物件中第一個非 pending 的 promise,我們可以檢查 promise 的狀態,包括它是否處於 pending 狀態。此示例改編自 promise-status-async。
function promiseState(promise) {
const pendingState = { status: "pending" };
return Promise.race([promise, pendingState]).then(
(value) =>
value === pendingState ? value : { status: "fulfilled", value },
(reason) => ({ status: "rejected", reason }),
);
}
在此函式中,如果 promise 處於 pending 狀態,第二個值 pendingState(它是一個非 promise)將成為 race 的結果;否則,如果 promise 已經 settled,我們可以透過 onFulfilled 和 onRejected 回撥來了解其狀態。例如:
const p1 = new Promise((res) => setTimeout(() => res(100), 100));
const p2 = new Promise((res) => setTimeout(() => res(200), 200));
const p3 = new Promise((res, rej) =>
setTimeout(() => rej(new Error("failed")), 100),
);
async function getStates() {
console.log(await promiseState(p1));
console.log(await promiseState(p2));
console.log(await promiseState(p3));
}
console.log("Immediately after initiation:");
getStates();
setTimeout(() => {
console.log("After waiting for 100ms:");
getStates();
}, 100);
// Logs:
// Immediately after initiation:
// { status: 'pending' }
// { status: 'pending' }
// { status: 'pending' }
// After waiting for 100ms:
// { status: 'fulfilled', value: 100 }
// { status: 'pending' }
// { status: 'rejected', reason: Error: failed }
注意: promiseState 函式仍然是非同步執行的,因為沒有辦法同步獲取 promise 的值(即,不使用 then() 或 await),即使它已經 settled。然而,promiseState() 始終在一個 tick 內 fulfills,並且實際上不會等待任何 promise 的 settlement。
與 Promise.any() 的比較
Promise.race 獲取第一個 settled 的 Promise。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "one");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, "two");
});
Promise.race([promise1, promise2])
.then((value) => {
console.log("succeeded with value:", value);
})
.catch((reason) => {
// Only promise1 is fulfilled, but promise2 is faster
console.error("failed with reason:", reason);
});
// failed with reason: two
Promise.any 獲取第一個 fulfilled 的 Promise。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "one");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, "two");
});
Promise.any([promise1, promise2])
.then((value) => {
// Only promise1 is fulfilled, even though promise2 settled sooner
console.log("succeeded with value:", value);
})
.catch((reason) => {
console.error("failed with reason:", reason);
});
// succeeded with value: one
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-promise.race |
瀏覽器相容性
載入中…