Promise.race的核心逻辑是:返回第一个settled(fulfilled或rejected)的Promise结果,状态不可逆且只决议一次;需用闭包变量标记是否已决议,防止重复调用,并用Promise.resolve包装输入项以兼容非Promise值。

Promise.race 的核心逻辑是:只要任意一个输入 Promise **率先改变状态(fulfilled 或 rejected)**,就立即以该结果(值或错误)决议(resolve/reject)返回的 Promise;后续其他 Promise 的状态变化应被忽略。这正依赖 Promise 状态「不可逆」和「只改变一次」的特性。
关键点:用闭包标记「是否已决议」
由于 Promise 构造函数内部无法直接判断「是否已被决议」,需借助外部变量(闭包)记录状态。一旦第一次调用 resolve 或 reject,就置标志位,后续所有回调都跳过。
- 定义一个布尔变量 settled = false,初始为 false
- 每次执行 resolve 或 reject 前,先检查 if (settled) return
- 确认未决议后,才更新状态并设 settled = true
手写实现(兼容 fulfilled 和 rejected)
注意:Promise.race 对首个 rejected 的 Promise 也会立即 reject,不是只等 fulfilled。
function PromiseRace(promises) {
return new Promise((resolve, reject) => {
let settled = false;
// 空数组直接 reject
if (!Array.isArray(promises) || promises.length === 0) {
reject(new TypeError('Argument must be an array'));
return;
}
for (let i = 0; i < promises.length; i++) {
// 确保每个项都转为 Promise(兼容非 Promise 值)
Promise.resolve(promises[i])
.then(value => {
if (!settled) {
settled = true;
resolve(value);
}
})
.catch(reason => {
if (!settled) {
settled = true;
reject(reason);
}
});
}
});
}
为什么能靠「状态只变一次」保证正确性?
Promise 规范明确要求:一个 Promise 实例的状态只能从 pending → fulfilled 或 pending → rejected,且不可逆转。构造函数中传入的 resolve 和 reject 函数本身具备防重入机制——多次调用时,只有第一次生效,其余静默忽略。我们加的 settled 只是提前拦截、避免无谓调用,本质仍是靠 Promise 内部的状态不可变性兜底。
立即学习“Java免费学习笔记(深入)”;
- 即使没写
if (!settled),多次调用 resolve/reject 也不会出错,但会浪费执行 - 加上该判断更高效、语义更清晰,也符合规范中「race 应尽快返回首个结果」的要求
- 不依赖它也能工作,但手写时显式控制是稳妥做法
小陷阱提醒
常见错误是只处理 fulfilled,漏掉 rejected 情况;或未用 Promise.resolve() 包装输入项,导致非 Promise 值(如字符串、数字)无法被 then/catch 捕获。
- Promise.race([1, Promise.resolve(2), Promise.reject('err')]) → 立即 reject('err')
- Promise.race(['a', 'b']) → 立即 resolve('a'),因为字符串被 Promise.resolve() 转为 resolved Promise
- 不包装原始值,
'a'.then会报错,导致 race 返回的 Promise 永远 pending


















