当前位置: 首页 > article >正文

Promise.race()

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

语法

Promise.race(iterable)

参数

iterable
一个 promise 可迭代对象(例如数组)。

返回值

一个 Promise,会以 iterable 中第一个敲定的 promise 的状态异步敲定。换句话说,如果第一个敲定的 promise 被兑现,那么返回的 promise 也会被兑现;如果第一个敲定的 promise 被拒绝,那么返回的 promise 也会被拒绝。如果传入的 iterable 为空,返回的 promise 就会一直保持待定状态。如果传入的 iterable 非空但其中没有任何一个 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 === "兑现") {
        return resolve(value);
      } else {
        return reject(new Error(value));
      }
    }, time);
  });
}

const p1 = sleep(500, "一", "兑现");
const p2 = sleep(100, "二", "兑现");

Promise.race([p1, p2]).then((value) => {
  console.log(value); // “二”
  // 两个都会兑现,但 p2 更快
});

const p3 = sleep(100, "三", "兑现");
const p4 = sleep(500, "四", "拒绝");

Promise.race([p3, p4]).then(
  (value) => {
    console.log(value); // “三”
    // p3 更快,所以它兑现
  },
  (error) => {
    // 不会被调用
  },
);

const p5 = sleep(500, "五", "兑现");
const p6 = sleep(100, "六", "拒绝");

Promise.race([p5, p6]).then(
  (value) => {
    // 不会被调用
  },
  (error) => {
    console.error(error.message); // “六”
    // p6 更快,所以它拒绝
  },
);

Promise.race 的异步性

以下示例演示了 Promise.race 的异步性。与其他 promise 并发方法不同,Promise.race 总是异步的:即使 iterable 为空,它也永远不会同步地完成。

// 传入一个已经解决的 Promise 数组,以尽快触发 Promise.race。
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

const p = Promise.race(resolvedPromisesArray);
// 立即打印 p 的值
console.log(p);

// 使用 setTimeout,我们可以在堆栈为空后执行代码
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(p);
});

// 按顺序打印:
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "fulfilled", <value>: 33 }

个空的可迭代对象会导致返回的 Promise 一直处于待定状态:

const foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(foreverPendingPromise);
});

// 按顺序打印:
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "pending" }

如果可迭代对象包含一个或多个非 Promise 值和/或一个已经敲定的 Promise,则 Promise.race 会以数组中找到的第一个这样的值敲定:

const foreverPendingPromise = Promise.race([]);
const alreadyFulfilledProm = Promise.resolve(100);

const arr = [foreverPendingPromise, alreadyFulfilledProm, "非 Promise 值"];
const arr2 = [foreverPendingPromise, "非 Promise 值", Promise.resolve(100)];
const p = Promise.race(arr);
const p2 = Promise.race(arr2);

console.log(p);
console.log(p2);
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(p);
  console.log(p2);
});

// 按顺序打印:
// Promise { <state>: "pending" }
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "fulfilled", <value>: 100 }
// Promise { <state>: "fulfilled", <value>: "非 Promise 值" }

使用 Promise.race() 实现请求超时

你可以使用一个定时器来与一个可能持续很长时间的请求进行竞争,以便超出时间限制时,返回的 Promise 自动拒绝。

const data = Promise.race([
  fetch("/api"),
  new Promise((resolve, reject) => {
    // 5 秒后拒绝
    setTimeout(() => reject(new Error("请求超时")), 5000);
  }),
])
  .then((res) => res.json())
  .catch((err) => displayError(err));

如果 data Promise 被兑现,它将包含从 /api 获取的数据;否则,如果 fetch 保持待定状态并输给 setTimeout 定时器,这个 Promise 将在 5 秒后被拒绝。

使用 Promise.race() 检测 Promise 的状态

由于 Promise.race() 解决的可迭代对象中第一个非待定状态的 Promise,我们可以检查一个 Promise 的状态,包括它是否处于待定状态。这个示例是从 promise-status-async 改编而来的。

function promiseState(promise) {
  const pendingState = { status: "待定" };

  return Promise.race([promise, pendingState]).then(
    (value) => (value === pendingState ? value : { status: "已兑现", value }),
    (reason) => ({ status: "已拒绝", reason }),
  );
}

在这个函数中,如果 promise 是待定状态,非 Promise 类型的第二个值 pendingState 将成为这个 race 的结果;否则,如果 promise 已经敲定,我们可以通过 onFulfilledonRejected 处理函数来知道它的状态。例如:

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("开始状态:");
getStates();
setTimeout(() => {
  console.log("等待 100ms 后:");
  getStates();
}, 100);

// 打印:
// 开始状态:
// { status: '待定' }
// { status: '待定' }
// { status: '待定' }
// 等待 100ms 后:
// { status: '已兑现', value: 100 }
// { status: '待定' }
// { status: '已拒绝', reason: 300 }

注意: promiseState 函数仍然是异步执行的,因为没有办法同步地获取 Promise 的值(即不使用 then()await),即使它已经敲定。但是,promiseState() 总是在一次事件循环内就会完成,并且实际上从不等待任何 Promise 的敲定。

与 Promise.any() 的比较

Promise.race 方法以可迭代对象中第一个敲定的 Promise 作为敲定值。

Promise.any 方法以可迭代对象中第一个被兑现的 Promise 作为兑现值。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "一");
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "二");
});

Promise.race([promise1, promise2])
  .then((value) => {
    console.log("成功,值为:", value);
  })
  .catch((reason) => {
    // 只有 promise1 成功兑现,但 promise2 更快
    console.error("失败,原因为:", reason);
  });
// 失败,原因为:二
Promise.any([promise1, promise2])
  .then((value) => {
    // 只有 promise1 成功兑现,即使 promise2 更快敲定
    console.log("成功,值为:", value);
  })
  .catch((reason) => {
    console.error("失败,原因为:", reason);
  });
// 成功,值为:一

http://www.kler.cn/a/354038.html

相关文章:

  • 大模型-ChatGLM2-6B模型部署与微调记录
  • 全面了解 SQL Server:功能、优势与最佳实践
  • Selenium+Java(21):Jenkins发送邮件报错Not sent to the following valid addresses解决方案
  • 无需训练!多提示视频生成最新SOTA!港中文腾讯等发布DiTCtrl:基于MM-DiT架构
  • C++ 设计模式:原型模式(Prototype Pattern)
  • import org.springframework.data.jpa.repository.JpaRepository<T, ID>;
  • 【python爬虫】携程旅行景点游客数据分析与可视化
  • Biotin-PEG-COOH 羧基-聚乙二醇-生物素的应用 蛋白质纯化 细胞标记
  • 如何将两个视频连接成一个?共有6个方法
  • 集成电路公司进销存系统生成合同——未来之窗行业应用跨平台架构
  • FreeRTOS - 任务通知
  • 锥线性规划【分布鲁棒、两阶段鲁棒方向知识点】
  • 基于SpringBoot的校园兼职管理系统
  • Scrapy | 爬取网易招聘信息来认识start_urls是POST请求时如何重写start_requests方法以及翻页问题的处理
  • 力扣题解(鸡蛋掉落,两枚鸡蛋)
  • Bug剖析
  • 数据权限的设计与实现系列12——前端筛选器组件Everright-filter集成功能完善3
  • 优化SpringBoot接口:异步处理提升系统吞吐量策略
  • SQL语句查询
  • 【IC设计】复旦微行业分析
  • 为什么你总碰到渣男?伯克森悖论
  • 博客搭建之路:hexo使用next主题渲染流程图
  • 技术总结(七)
  • 解决ultralytics中的YOLOv8在执行task.py文件添加模块操作出现的KeyError报错
  • Linux-lvs
  • 芒果YOLOv10改进136:注意力机制MLLA|即插即用:融合Mamba设计精髓的线性注意力视觉Transformer