Promise.race()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

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"

语法

js
Promise.race(iterable)

参数

iterable

一个 promise 的 可迭代对象(例如 Array)。

返回值

一个 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 的状态。

js
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 为空。

js
// 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 状态

js
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。

js
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。

js
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

js
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,我们可以通过 onFulfilledonRejected 回调来了解其状态。例如:

js
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

js
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

js
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

浏览器兼容性

另见