登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
23
Star
192
Fork
47
yanleweb
/
interview-question
代码
Issues
1091
Pull Requests
0
Wiki
统计
流水线
服务
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
请求数量过多,该如何治理【热度: 418】
待办的
#IARJAI
yanleweb
拥有者
创建于
2024-09-15 14:53
**关键词**:治理请求数量 > 作者备注 > 很多同学我有 http2 , 可以多路复用, 所以请求再多都不会影响页面性能。 实际上是错误的。 > 在作者知道的很多超大型项目(千万行级别的项目)里面, 太多的网络并发(首屏可能就有好大几百的请求发出去), 会因为 IO 问题到时吃掉很多的 CPU 与网络带宽, 用户依然会觉得非常的卡顿。 > 所以这个话题是非常有意义的。 但是实际中遇到请求过多的问题, 场景是非常少的。 > 目前作者暂定 该问题级别为 「资深」 > 而且该问题没有一个准确的答案, 作者在这里知识提供干一些思路。 **1. 常量请求做本地内存存储** 不是使用 https 缓存, 而是直接存一个 promise 在浏览器内存里面。 保证整个系统里面, 请求只调用一次。 对于一些数据不经常变化的请求,例如用户信息、配置数据等,可以将请求的结果缓存起来。下一次请求相同的资源时,先从缓存中读取数据,如果缓存有效,则无需再发起新的网络请求。 思路类似于下面这张图  要达到这样的效果,可以设计一个请求缓存管理器,来管理并发的请求。如果有相同的请求(URL、参数、方法相同)时,只发起一次网络调用,然后将结果分发给所有等待的请求。这种模式通常可以通过一个简单的缓存对象来实现,该对象将请求的唯一标识作为键,对应的 Promise 作为值。 以下是一个基本实现的示例: ```javascript class RequestCache { constructor() { this.cache = new Map(); } // 生成请求的唯一标识符,这里仅以 URL 和 Method 为例,实际可能需要包括请求体等 generateKey(url, method) { return `${method}:${url}`; } // 执行请求的方法,接受 fetch 的所有参数 request(url, options = {}) { const { method = "GET" } = options; const key = this.generateKey(url, method); // 检查缓存中是否有相同的请求 if (this.cache.has(key)) { return this.cache.get(key); } // 没有相同的请求,发起新的请求 const requestPromise = fetch(url, options) .then((response) => response.json()) .then((data) => { // 请求成功后,将其从缓存中移除 this.cache.delete(key); return data; }) .catch((error) => { // 请求失败也应该从缓存中移除 this.cache.delete(key); throw error; }); // 将新的请求 Promise 保存在缓存中 this.cache.set(key, requestPromise); return requestPromise; } } // 使用示例 const cache = new RequestCache(); const URL = "https://api.example.com/data"; // 假设这三个请求几乎同时发起 cache.request(URL).then((data) => console.log("请求1:", data)); cache.request(URL).then((data) => console.log("请求2:", data)); cache.request(URL).then((data) => console.log("请求3:", data)); ``` 这个简单的 `RequestCache` 类通过一个内部的 `Map` 对象管理缓存的请求。当一个新的请求发起时,它会首先检查是否已经有相同的请求存在。如果已存在,那么它只返回先前请求的 Promise;如果不存在,它会发起一个新的网络请求,并将请求的 Promise 存储在缓存中,直到请求完成(无论是成功还是失败)之后,再将其从缓存中移除。 请注意,这里的示例非常基础,且主要用于说明如何缓存并复用请求的结果。在实际应用中,你可能还需要考虑更多细节,比如如何更精细地处理 POST 请求的请求体内容、如何设置缓存的过期时间、错误处理策略、缓存大小限制等。 **推荐参考文档**: https://juejin.cn/post/7341840038964363283 **2. 合并请求** 对于多个小请求,特别是对同一个服务器或 API 的调用,考虑将它们合并为一个较大的请求。例如,如果有多个 API 分别获取用户信息、用户订单、用户地址等,可以考虑后端提供一个合并接口,一次性返回所有所需数据。 **3. 使用 Web 缓存** - **浏览器缓存**:利用 HTTP 缓存头控制静态资源(CSS、JS、图片)的缓存策略,减少重复请求。 - **数据缓存**:对于 AJAX 请求的响应,可以在前端进行数据缓存,避免短时间内对相同资源的重复请求。 **4. 延迟加载(懒加载)** 对于非首屏必须的资源(如图片、视频、长列表等),可以采用延迟加载或懒加载的方式,只有当用户滚动到相应位置时才加载这些内容,减少初次加载时的请求数量。 **5. 使用服务工作线程(Service Workers)** 通过 Service Workers 可以拦截和缓存网络请求,实现离线体验,减少对服务器的请求。此外,Service Workers 还可以用于请求合并、请求失败的重试策略等。 **6. 避免重复请求** 在某些情况下,为了保证数据的实时性,前端可能会频繁地轮询服务器。可以通过设置合理的轮询间隔或采用基于 WebSocket 的实时数据推送方案,以减少请求次数。 **7. 使用 GraphQL** 对于 REST API 可能导致的过度取数据(over-fetching)或取少数据(under-fetching)问题,可以考虑使用 GraphQL。GraphQL 允许客户端准确指定所需数据的结构,一次请求准确获取所需信息,减少无效数据的传输。 **8. 防抖和节流** 在处理连续的事件触发对后端的请求(如输入框实时搜索、窗口大小调整等)时,使用防抖(debouncing)和节流(throttling)技术可以限制触发请求的频率,减少不必要的请求量。
**关键词**:治理请求数量 > 作者备注 > 很多同学我有 http2 , 可以多路复用, 所以请求再多都不会影响页面性能。 实际上是错误的。 > 在作者知道的很多超大型项目(千万行级别的项目)里面, 太多的网络并发(首屏可能就有好大几百的请求发出去), 会因为 IO 问题到时吃掉很多的 CPU 与网络带宽, 用户依然会觉得非常的卡顿。 > 所以这个话题是非常有意义的。 但是实际中遇到请求过多的问题, 场景是非常少的。 > 目前作者暂定 该问题级别为 「资深」 > 而且该问题没有一个准确的答案, 作者在这里知识提供干一些思路。 **1. 常量请求做本地内存存储** 不是使用 https 缓存, 而是直接存一个 promise 在浏览器内存里面。 保证整个系统里面, 请求只调用一次。 对于一些数据不经常变化的请求,例如用户信息、配置数据等,可以将请求的结果缓存起来。下一次请求相同的资源时,先从缓存中读取数据,如果缓存有效,则无需再发起新的网络请求。 思路类似于下面这张图  要达到这样的效果,可以设计一个请求缓存管理器,来管理并发的请求。如果有相同的请求(URL、参数、方法相同)时,只发起一次网络调用,然后将结果分发给所有等待的请求。这种模式通常可以通过一个简单的缓存对象来实现,该对象将请求的唯一标识作为键,对应的 Promise 作为值。 以下是一个基本实现的示例: ```javascript class RequestCache { constructor() { this.cache = new Map(); } // 生成请求的唯一标识符,这里仅以 URL 和 Method 为例,实际可能需要包括请求体等 generateKey(url, method) { return `${method}:${url}`; } // 执行请求的方法,接受 fetch 的所有参数 request(url, options = {}) { const { method = "GET" } = options; const key = this.generateKey(url, method); // 检查缓存中是否有相同的请求 if (this.cache.has(key)) { return this.cache.get(key); } // 没有相同的请求,发起新的请求 const requestPromise = fetch(url, options) .then((response) => response.json()) .then((data) => { // 请求成功后,将其从缓存中移除 this.cache.delete(key); return data; }) .catch((error) => { // 请求失败也应该从缓存中移除 this.cache.delete(key); throw error; }); // 将新的请求 Promise 保存在缓存中 this.cache.set(key, requestPromise); return requestPromise; } } // 使用示例 const cache = new RequestCache(); const URL = "https://api.example.com/data"; // 假设这三个请求几乎同时发起 cache.request(URL).then((data) => console.log("请求1:", data)); cache.request(URL).then((data) => console.log("请求2:", data)); cache.request(URL).then((data) => console.log("请求3:", data)); ``` 这个简单的 `RequestCache` 类通过一个内部的 `Map` 对象管理缓存的请求。当一个新的请求发起时,它会首先检查是否已经有相同的请求存在。如果已存在,那么它只返回先前请求的 Promise;如果不存在,它会发起一个新的网络请求,并将请求的 Promise 存储在缓存中,直到请求完成(无论是成功还是失败)之后,再将其从缓存中移除。 请注意,这里的示例非常基础,且主要用于说明如何缓存并复用请求的结果。在实际应用中,你可能还需要考虑更多细节,比如如何更精细地处理 POST 请求的请求体内容、如何设置缓存的过期时间、错误处理策略、缓存大小限制等。 **推荐参考文档**: https://juejin.cn/post/7341840038964363283 **2. 合并请求** 对于多个小请求,特别是对同一个服务器或 API 的调用,考虑将它们合并为一个较大的请求。例如,如果有多个 API 分别获取用户信息、用户订单、用户地址等,可以考虑后端提供一个合并接口,一次性返回所有所需数据。 **3. 使用 Web 缓存** - **浏览器缓存**:利用 HTTP 缓存头控制静态资源(CSS、JS、图片)的缓存策略,减少重复请求。 - **数据缓存**:对于 AJAX 请求的响应,可以在前端进行数据缓存,避免短时间内对相同资源的重复请求。 **4. 延迟加载(懒加载)** 对于非首屏必须的资源(如图片、视频、长列表等),可以采用延迟加载或懒加载的方式,只有当用户滚动到相应位置时才加载这些内容,减少初次加载时的请求数量。 **5. 使用服务工作线程(Service Workers)** 通过 Service Workers 可以拦截和缓存网络请求,实现离线体验,减少对服务器的请求。此外,Service Workers 还可以用于请求合并、请求失败的重试策略等。 **6. 避免重复请求** 在某些情况下,为了保证数据的实时性,前端可能会频繁地轮询服务器。可以通过设置合理的轮询间隔或采用基于 WebSocket 的实时数据推送方案,以减少请求次数。 **7. 使用 GraphQL** 对于 REST API 可能导致的过度取数据(over-fetching)或取少数据(under-fetching)问题,可以考虑使用 GraphQL。GraphQL 允许客户端准确指定所需数据的结构,一次请求准确获取所需信息,减少无效数据的传输。 **8. 防抖和节流** 在处理连续的事件触发对后端的请求(如输入框实时搜索、窗口大小调整等)时,使用防抖(debouncing)和节流(throttling)技术可以限制触发请求的频率,减少不必要的请求量。
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
网络
阿里巴巴
未设置
标签管理
里程碑
资深
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (1)
标签 (64)
master
0.0.76
0.0.75
0.0.74
0.0.73
0.0.72
0.0.71
0.0.70
0.0.69
0.0.68
0.0.67
0.0.66
0.0.65
0.0.64
0.0.63
0.0.62
0.0.61
0.0.60
0.0.59
0.0.58
0.0.57
0.0.56
0.0.55
0.0.54
0.0.53
0.0.52
0.0.51
0.0.50
0.0.49
0.0.48
0.0.47
0.0.46
0.0.45
0.0.44
0.0.43
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.29
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
TypeScript
1
https://gitee.com/yanleweb/interview-question.git
git@gitee.com:yanleweb/interview-question.git
yanleweb
interview-question
interview-question
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册