Promise.race()
该Promise.race()
静态方法将可迭代的 Promise 作为输入,并返回单个Promise
。此返回的 Promise 最终会使用第一个解决的 Promise 的状态进行解决。
试一试
语法
Promise.race(iterable)
参数
返回值
一个Promise
,它异步解决iterable
中第一个解决的 Promise 的最终状态。换句话说,如果第一个解决的 Promise 已完成,则它会完成;如果第一个解决的 Promise 已拒绝,则它会拒绝。如果传递的可迭代对象为空,则返回的 Promise 将永远保持挂起状态。如果传递的可迭代对象非空,但不包含任何挂起的 Promise,则返回的 Promise 仍然是异步(而不是同步)解决。
描述
该Promise.race()
方法是Promise 并发方法之一。当您希望第一个异步任务完成但并不关心其最终状态(即它可以成功或失败)时,它很有用。
如果可迭代对象包含一个或多个非 Promise 值和/或已解决的 Promise,则Promise.race()
将解决可迭代对象中找到的第一个这些值。
示例
使用 Promise.race()
此示例显示了如何Promise.race()
用于竞赛使用setTimeout()
实现的多个计时器。具有最短时间间隔的计时器始终赢得比赛,并成为结果 Promise 的状态。
function sleep(time, value, state) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (state === "fulfill") {
return resolve(value);
} else {
return 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
始终是异步的:它永远不会同步解决,即使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 永久挂起
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 值和/或已解决的 Promise,则Promise.race
将解决数组中找到的第一个这些值
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() 实现请求超时
您可以将一个可能持续时间很长的请求与一个拒绝的计时器进行竞争,以便当时间限制到期时,结果 Promise 会自动拒绝。
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 已完成,它将包含从/api
; 否则,如果fetch
在 5 秒内保持挂起状态并输给setTimeout
计时器,则它将被拒绝。
使用 Promise.race() 检测 Promise 的状态
因为Promise.race()
解析为可迭代对象中的第一个非挂起 Promise,所以我们可以检查 Promise 的状态,包括它是否正在挂起。此示例改编自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
正在挂起,则第二个值pendingState
,它是一个非 Promise,成为竞赛的结果;否则,如果promise
已解决,我们可以通过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(300), 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: 300 }
注意:该promiseState
函数仍然异步运行,因为无法同步获取 Promise 的值(即不使用then()
或await
),即使它已解决。但是,promiseState()
始终在一个 Tick 内完成,并且实际上从未等待任何 Promise 的解决。
与 Promise.any() 的比较
Promise.race
采用第一个已解决的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
采用第一个已完成的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 语言规范 # sec-promise.race |
浏览器兼容性
BCD 表格仅在启用了 JavaScript 的浏览器中加载。