如何在高并发环境下利用 Promise.any 建立一套具备快速响应能力的网关

夜芳大大_1156

夜芳大大_1156

2026-04-24

277人浏览

原创

promise.any 更适合作为网关“首响策略”,因为它只认成功——任一后端返回200即立刻resolve,其余失败或慢响应自动忽略;而promise.race会因首个reject(如超时)导致整体失败,违背高可用目标。

如何在高并发环境下利用 promise.any 建立一套具备快速响应能力的网关

Promise.any 为什么比 Promise.race 更适合作为网关的“首响策略”

因为 Promise.race 会把第一个失败的 Promise 当作整体失败,而网关最怕的是“明明有服务能响应,却被一个抖动节点拖垮”。Promise.any 只认成功——只要有一个后端实例返回 200,它就立刻 resolve,其余失败或慢响应的请求自动被忽略。这在多活部署、CDN 回源、灰度流量分发等场景中,直接决定了用户是否看到“加载中”还是“内容已呈现”。

常见错误现象:Promise.race([fetch('/api/v1'), fetch('/api/v2')]) 中若 /api/v1 因网络超时 reject(比如 300ms),即使 /api/v2 在 400ms 后正常返回,整个请求也已失败。而 Promise.any 会耐心等到 400ms 那个成功结果。

  • 关键区别:race 是“谁先变状态谁说了算”,any 是“谁先成功谁说了算”
  • 适用前提:所有并行请求语义等价(返回相同结构数据),且你接受“最快那个”的结果
  • 不适用场景:需要聚合多个结果(用 Promise.all)、或必须等待全部完成才敢做下一步(如风控双校验)

如何构造一组语义等价但物理隔离的请求源

网关层不能只靠改 Promise 方法就提升可用性;真正起作用的是背后那组可互换的后端地址。比如:

  • 主站 API + 备用集群(同机房不同宿主机)
  • CDN 边缘节点(https://cdn-a.example.com)+ 源站直连(https://origin.example.com)
  • 不同云厂商的同构服务(https://api-us-west-1.example.com / https://api-ap-southeast-1.example.com)

注意:这些 URL 必须返回完全兼容的响应体(字段名、类型、嵌套结构一致),否则前端解析会出错。建议用 OpenAPI Schema 做契约校验,而非仅靠人工约定。

示例代码片段(构造请求数组):

const endpoints = [
  fetch('/api/data', { signal: AbortSignal.timeout(800) }),
  fetch('https://cdn.example.com/api/data', { signal: AbortSignal.timeout(800) }),
  fetch('https://backup.example.com/api/data', { signal: AbortSignal.timeout(1200) })
];

这里每个 fetch 都带独立超时,避免某个节点卡死拖累全局。

如何处理 Promise.any 全部失败的 AggregateError

Promise.any 全部失败时抛出 AggregateError,其 errors 属性是包含所有 rejection 原因的数组。这比单个 error 有用得多——你能知道是 DNS 解析失败、连接超时,还是后端返回了 503。

  • 别直接 console.error(err):它不会展开 errors 数组,看起来像空对象
  • 正确做法是遍历 err.errors,按错误类型分类记录(例如:网络类错误打 warning,5xx 错误打 error)
  • 对用户可降级显示:“正在尝试其他线路…” 而非“请求失败”,同时后台自动触发告警

示例错误处理逻辑:

Promise.any(endpoints)
  .then(res => res.json())
  .catch(err => {
    if (err.name === 'AggregateError') {
      err.errors.forEach((e, i) => {
        console.warn(`[any-fail-${i}]`, e.toString());
      });
      // 触发降级逻辑,如返回缓存、静态兜底页
      return getFallbackData();
    }
    throw err;
  });

并发池 + Promise.any 的组合陷阱

很多文章教你在 PromisePool 里用 Promise.any(this.pool) 监听任意完成,但容易忽略一个关键点:当某次 Promise.any 返回后,你得确保后续进来的任务仍能被监听到,否则池子会“卡住”。

  • 错误写法:只调一次 Promise.any,然后靠 .then 往池子里塞新任务,但没重新调用 Promise.any —— 新任务永远进不了监听队列
  • 正确做法:每次有任务完成(无论成功或失败),都从池中移除它,并立即对剩余 pool 再调一次 Promise.any,形成持续监听链
  • 性能影响:频繁创建 Promise.any 实例开销极小,但若池中长期只剩 1 个任务,相当于退化为串行,需配合最小并发数兜底

最容易被忽略的地方是:你得在每个子 Promise 的 .finally 里做清理和重监听,而不是只在 .then 或 .catch 里——否则失败任务不触发后续调度。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4646

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1169

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4584

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

920

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1816

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3325

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

4313

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

2820

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

888

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习