本文目录导读:
减少请求数是前端性能优化、后端服务优化以及网络优化的核心目标之一,请求数越少,意味着建立的 TCP 连接越少、DNS 查询越少、握手开销越小,页面加载速度会显著提升。
以下从前端策略、后端策略、网络策略和架构策略四个维度,系统性地说明如何减少请求数。
前端策略(最常用,立竿见影)
资源合并与打包(Bundling)
- CSS/JS 合并:将多个 CSS 文件合并为一个,多个 JS 文件合并为一个,使用 Webpack、Vite、Rollup 等打包工具。
- 雪碧图(CSS Sprites):将多个小图标合并到一张大图上,通过
background-position定位。注意:现在更推荐使用 SVG 图标或字体图标,它们只需一次请求。 - 图片内联(Base64/Data URL):将非常小的图片(如 1x1 像素的透明图、小图标)转为 Base64 字符串直接写在 CSS/HTML 中,避免 HTTP 请求,通常只针对 2KB-10KB 以下的图片。
使用缓存策略(不是减少请求,而是减少无效请求)
- 强缓存:通过设置
Cache-Control: max-age=31536000,让浏览器在有效期内完全不发请求。 - 协商缓存:通过
ETag或Last-Modified,当资源未变化时,服务器返回 304,不传输内容。
代码与资源优化
- 图片懒加载:对于长列表页面,只加载可视区域的图片,其余图片用占位符替代。
- 组件懒加载(Lazy Load):使用
React.lazy()、import()或 Vue 的异步组件,让首屏只加载必要的 JS 代码。 - 无限滚动与虚拟列表:对于数万条数据,使用虚拟列表只渲染可见部分,而不是一次性请求所有数据。
减少外部资源与第三方库
- 使用 CDN 的版本控制:如果使用 CDN 上的第三方库(如 jQuery、Lodash),尽量使用同一个 CDN 且版本固定。
- 减少字体文件:只加载需要的字体子集,而不是整个字体包。
- 移除不必要的库:例如用原生 JS 替代 jQuery,用 CSS 动画替代动画库。
后端策略(接口层)
API 合并与数据聚合(GraphQL/BFF)
- GraphQL:客户端可以指定需要的数据字段,一次性获取多个关联资源的数据,避免多次 REST 请求。
- BFF(Backend For Frontend):在前端和后端之间加一层中间层(如 Node.js),将多个微服务的接口聚合为一个接口返回。
- 批量接口(Batch API):提供一个
/batch接口,允许客户端在请求体中传入多个 API 的调用参数,后台统一处理并返回。
避免“瀑布流”请求
- 使用 Promise.all 并发请求,而不是串行等待(虽然不减少请求数,但减少等待时间)。
- 后端提供一次性返回关联数据的接口(请求用户信息时,直接返回用户
所属团队和最近订单的列表,而不是前端再发两次请求)。
使用 WebSocket 替代轮询
- 对于实时更新的场景(如聊天、通知、价格变化),不要使用
setInterval定时发 HTTP 请求去轮询。 - 使用 WebSocket 或 Server-Sent Events (SSE) 建立长连接,服务器主动推送数据,只建立一次连接。
网络与架构策略
HTTP/2 多路复用(不是严格减少请求,但节省连接)
- HTTP/2 支持多路复用,可以在一个 TCP 连接上并行发送多个请求和响应,虽然请求数没变,但消除了队头阻塞,减少了 TCP 连接建立的开销。
- 注意:如果用了 HTTP/2,就不要强行合并 CSS/JS 了(反而会影响缓存粒度),可以适当拆分为更小粒度的文件,利用缓存优势。
使用 CDN
- 将静态资源部署到 CDN 节点,用户从最近的节点获取资源,请求数不变,但请求的距离和时间大大缩短。
- CDN 还可以做预解析,提前解析 DNS。
预加载与预连接
<link rel="preload">:提前加载关键资源(如字体、首屏图片、关键 CSS)。<link rel="preconnect">:提前与第三方服务器(如 Google Fonts、CDN)建立 TCP 连接,减少后续请求的握手时间。<link rel="dns-prefetch">:提前完成 DNS 域名解析。
架构级手段
服务端渲染(SSR)或静态站点生成(SSG)
- SSR:在服务端渲染好 HTML 返回,客户端不需要发 Ajax 请求去获取初始数据,首屏请求数从“1个HTML + 多个API请求”减少为“1个HTML”。
- SSG:构建时生成所有 HTML 页面,访问时直接返回静态文件,无需调用后端服务。
采用微前端或微服务架构治理
- 将不同业务模块拆分成独立部署的子应用,但通过统一的调度层,按需加载子应用的代码,避免加载整个 SPA 应用的所有代码。
总结与最佳实践清单
| 场景 | 建议手段 | 效果 |
|---|---|---|
| 静态资源(JS/CSS/图片) | 合并、雪碧图、Base64 内联、使用 CDN + 强缓存 | 减少大量 HTTP 连接 |
| 首屏数据 | SSR / SSG / 后端聚合 / GraphQL | 从 N 次请求变为 1 次 |
| 多个小接口 | 合并为一个批量接口 / BFF 层 | 减少多次往返 |
| 实时数据 | WebSocket / SSE | 从定时轮询变为一次连接 |
| 重复请求 | 设置合理的 Cache-Control / ETag |
浏览器不发请求(304) |
| 列表/长页 | 懒加载、虚拟滚动、无限滚动 | 减少非可视区域请求 |
核心思路:能缓存就不请求,能合并就不拆分,能推流就不轮询,能内联就不外链。 在实际项目中,建议结合性能监控工具(如 Chrome DevTools 的 Network 面板、Lighthouse)分析请求瀑布图,找到最耗时的“长尾请求”和“串联请求”,针对性解决。