☰
减少不必要的传输:前端性能优化的架构级实践
2026/9/29 17:58:24 网站建设 项目流程

最近在优化一个老项目的前端性能时,同事问了我一个很实在的问题:“后端接口已经很快了,为什么页面还是慢?”我让他开 Chrome DevTools 的 Network 面板,截图里最扎眼的不是某一个请求多慢,而是密密麻麻几十个请求、每个响应头里都带着大大的content-encoding: gzip,但资源本身却依然像“注水”一样臃肿。这件事让我想起很多备考软考系统架构师的朋友,经常在案例题里看到“前端优化”四个字,第一反应就是上 CDN、加缓存,却忽略了最底层也最容易被架构视角覆盖的那件事——减少不必要的传输。

“减少不必要的传输”不是单纯把图片压小一点、把 JS 合并一下那么简单。它牵扯到网络协议、缓存策略、代码结构、服务端协作,甚至产品需求本身。这篇文章我想用做过的项目里的真实经验和踩过的坑,把这节内容拆开讲透。适合正在准备系统架构师考试的同学,更适合那些写页面时觉得“网络请求太多”“包太大”却不知道怎么系统下手的前端工程师。

1. 先想清楚:为什么“减少不必要的传输”是架构师的第一功课

1.1 传输开销的构成,远比“带宽”两个字复杂

很多开发者在评估页面性能时,本能地只看“这个文件多少 KB”。但站在架构师的角度,一次资源传输的成本应该拆成三块:连接建立的开销、数据到达的开销、浏览器渲染前等待的开销。

以最普通的 HTTPS 请求为例。用户点击页面,浏览器先要做 DNS 解析,拿到 IP;然后和服务器建立 TCP 连接,完成 TLS 握手。这一套流程哪怕服务器在本地,也能吃掉几十毫秒;如果用户网络是跨地域的真实移动网络,轻松超过 200 毫秒。之后才开始真正传输响应体。这还没算上浏览器对同一域名并发连接数的限制,以及 HTTP/2 下多路复用里队头阻塞的残留影响。

所以“减少不必要的传输”里的“传输”两个字,不单指字节数,还指传输的次数、传输的时机、传输的链路层级。我见过一个极端案例:某项目每次进入首页,光基础配置接口就调用 5 次,返回内容几乎完全一样。优化前大家都觉得接口本身只有十几 KB,没什么大不了。但算上重复的 TLS 握手和排队等待,5 次请求在慢网环境下多消耗了近 2 秒。这种成本,只盯着单个文件体积是永远看不见的。

1.2 用“字节-时间-金钱”三维模型说服团队

做架构设计不能靠“感觉慢”,要让数据说话。我自己的习惯是给优化项建一个三维评估模型:字节数减少多少,关键耗时减少多少,运维成本变化多少。

举个例子。某个管理后台首页加载了一个 2MB 的完整 Ant Design 组件库代码,接口返回 300 条业务数据,但表格只展示前 20 条。从字节角度看:代码改成按需引入后,首屏 JS 从 2MB 降到 400KB;接口改成只返回当前页数据后,响应体从 300KB 降到 20KB。从时间角度看:慢网环境下,首屏可交互时间从 8 秒降到 3 秒。从成本角度看:CDN 流量费直接下降了 60%。

这个模型最有用的一点,是能帮你说服产品经理和运维。因为“减少不必要的传输”往往会涉及接口结构变更、缓存规则调整,甚至有短期风险。如果没有量化目标,很容易被一句“先这样吧”打回来。我在内部评审时会把每个优化项写成表格,标明预期收益和回滚方案,这样推动落地的阻力会小很多。

2. 从源头减少字节数:内容体积的压缩与消重

2.1 代码层:按需加载才是最大头,压缩只是“锦上添花”

很多同学以为减小传输就是把代码跑一遍压缩插件。实际做下来,压缩(minify)带来的收益通常只有 20% 到 30%,而按需加载和消除重复代码带来的收益可能超过 70%。

先说压缩。现在主流的构建工具 Webpack、Vite 在 production 模式下默认都会做 JS 压缩和 tree-shaking。Tree-shaking 能帮你移除那些 import 了但没有真正使用的模块导出。但要注意,它对有副作用的模块、CommonJS 格式的模块支持并不完美。我在一个老项目中就遇到过:第三方库是通过require方式引入的,tree-shaking 完全没有生效,最后手动改成按需引用,包体积立减一半。所以如果你发现压缩后体积还是大,先检查是不是有旧模块没有 ES Module 化。

代码分割才是控制传输的关键。架构层面要把“路由级别懒加载”当作底线。做法很简单:

// 原来:一次性引入 import UserManage from './pages/UserManage.vue' // 优化后:路由懒加载 const UserManage = () => import('./pages/UserManage.vue')

这样用户访问首页时,只有首页相关代码会被下载;进入用户管理页面时,才加载对应的 JS chunk。对于大型后台系统,这是收益最高、成本最低的改造之一。

再来是“消重”。很多项目在多个页面里各自封装了 request 函数、日期格式化工具,结果同一个工具函数被打进了不同的 chunk。架构上应该把这些公共逻辑抽成 shared 模块或组件库,并确保构建工具的splitChunks规则把公共依赖单独打包。Webpack 中的splitChunks.cacheGroups配置可以这么写:

// webpack.config.js optimization: { splitChunks: { cacheGroups: { vendor: { test: /node_modules/, name: 'vendor', chunks: 'all', }, shared: { test: /src\/shared/, name: 'shared', minChunks: 2, chunks: 'all', } } } }

不要盲目把 node_modules 全打成一个包。如果某个第三方库只在用户中心用到,而它又被塞进基础 vendor 里,首屏传输就会被白白拖累。按minChunks: 2的方式提取共享代码,通常更合理。

2.2 资源层:图片、字体和 CSS 的那些“隐形胖子”

前端页面里最容易“注水”的资源是图片。一个桌面端背景图原图 3MB,把它交给浏览器原样展示,是最典型的不必要传输。架构上要建立一套静态资源处理规范:图片必须经过压缩、格式转换、尺寸适配三步。

现在主流格式是 WebP 和 AVIF。以同样视觉效果为例,WebP 通常比 JPEG 小 25% 到 35%,AVIF 比 WebP 还能再小约 20%。但 AVIF 的兼容性目前仍然不如 WebP,所以稳妥做法是使用<picture>元素配合type属性做降级:

<picture> <source type="image/avif" srcset="banner.avif"> <source type="image/webp" srcset="banner.webp"> <img src="banner.jpg" alt="banner"> </picture>

如果项目里图片是后端上传的,建议在服务端做动态图片处理,通过 URL 参数指定宽高和质量。上传原图只存一份,输出时按需裁剪,既节省存储,又避免把 4000px 宽的原图传给只显示 400px 的移动端。

字体也是被忽略的大头。使用中文网站的完整字体文件动辄几 MB,哪怕只用了十几个汉字,也会被当作全量字体传输。解决办法是字体子集化,用工具(如 Fontmin、glyphhanger)把字体文件裁切成只包含用到的字符。更进一步,可以使用font-display: swap让字体加载阶段先显示降级字体,避免阻塞渲染。

CSS 层面要小心“合并所有 CSS 到一个文件”这种过时思路。HTTP/2 时代,连接复用能力强,文件合并反而破坏浏览器缓存粒度。比如某个页面只需要一部分 CSS,强行合并后所有页面都要下载同一份全量 CSS。更合理的做法是按页面或组件维度拆分 CSS,配合代码分割自动加载。

2.3 传输层压缩:Gzip 与 Brotli 的选型和配置

“减少不必要的传输”绕不开文本压缩。HTTP 响应体中的 JS、CSS、HTML 和 JSON 都是文本,压缩率极高。

目前最常用的两种算法是 Gzip 和 Brotli。Brotli 在压缩率和解码速度上通常优于 Gzip,但在较老的浏览器上支持不全,且对服务器 CPU 压力稍高。我的实践建议是:面向桌面端管理系统、用户浏览器版本较新时,优先开启 Brotli;面向兼容要求极高的场景,至少开启 Gzip 作为兜底。

Nginx 中的典型配置如下:

gzip on; gzip_static on; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript application/xml; # 如果开启 brotli 模块 brotli on; brotli_static on; brotli_comp_level 5; brotli_types text/plain text/css application/json application/javascript application/xml;

这里要注意gzip_static on的作用:它会直接使用构建目录里预生成的.gz文件,而不是每次请求时都实时压缩。这样做能大幅降低服务器 CPU 消耗。同理,构建工具方面,Vite 的vite-plugin-compression或 Webpack 的CompressionPlugin可以在构建阶段同时产出.gz和.br文件。

我还踩过一个坑:对本来已经压缩过的图片、PDF 等二进制资源再做 Gzip,纯属浪费服务器时间,体积也几乎不会变小。所以gzip_types里别加image/jpeg,加了也没用。

3. 避免重复传输:缓存策略的架构级设计

3.1 强缓存与协商缓存,本质是“要不要发请求”的问题

前端优化里经常被误解的一点是:配置了 HTTP 缓存,请求就变少了。其实不是。HTTP 缓存分为强缓存和协商缓存两档。

强缓存生效时,浏览器根本不发请求,直接使用本地副本。对应响应头是Cache-Control: max-age=31536000这类指令。协商缓存生效时,浏览器会发送一个请求,但服务器可以返回304 Not Modified,响应体不再传输。对应响应头是Last-Modified/ETag。

对于架构师来说,策略要分层:

  • 带版本号的静态资源(如app.a1b2c3.js):使用强缓存,Cache-Control: max-age=31536000, immutable。因为文件内容变了,文件名就变了,不存在更新问题。
  • 不带版本号的 HTML 文档:一般不能强缓存,或只能短缓存。用协商缓存或Cache-Control: no-cache(不是no-store,是允许协商)。
  • 需要实时性的接口:不允许浏览器缓存,避免数据过期。响应头一般设Cache-Control: no-store。

这个分层听起来简单,但很多项目把 HTML 也设置成max-age=86400,结果上线后生产环境用户把旧页面缓存了一天,静态资源和页面版本对不上,白屏一片。缓存配置涉及发布联动,一定要在设计评审阶段定好。

3.2 版本化文件名、CDN 和缓存失效的协作

上面提到的带版本号文件名,实现方式已经集成在现代构建工具里。例如 Vite 构建后会生成index-8f9a2b.js,这个哈希是根据文件内容生成的。只要内容没变,文件名就不变,浏览器和 CDN 就能放心命中缓存。

CDN 是把“减少不必要的传输”做到极致的环节。互联网长距离传输再快,也不如让用户从就近节点拿资源。架构上一般用两到三层缓存:CDN 边缘节点缓存静态资源;源站设置合理响应头;浏览器本地缓存兜底。

这里分享一个容易踩坑的细节:CDN 回源时会改写部分请求头,导致缓存未能生效。曾经排查一个项目,明明静态资源带了Cache-Control: max-age=31536000,但 CDN 仍然频繁回源。最后发现是 CDN 默认忽略源站的Cache-Control,需要单独在 CDN 控制台配置“缓存源站响应头”或者手动设置 CDN 缓存规则。

另外,如果使用 CDN 但新版本带上哈希后,旧版本文件不会立即失效,占用 CDN 空间,但这个空间成本通常可控,不要因此放弃强缓存策略。比较建议在发布系统里增加一个“CDN 刷新”步骤,只刷新 HTML 入口资源,静态哈希文件不需要刷新。

3.3 动态数据和用户私有内容的缓存边界

不是所有接口都不能缓存。有些数据变化频率低,比如“省市区列表”“系统配置项”“用户权限字典”,完全可以让浏览器或 CDN 缓存。可以在服务端接口返回里设置:

Cache-Control: public, max-age=300

5 分钟内用户重复请求,浏览器直接返回缓存,根本不走网络。这个改动比优化接口响应体更“暴力”,因为它连请求都省了。

但用户私有数据必须带上Cache-Control: private, no-store或者至少private, max-age=0。有一次我见过管理后台的订单接口被某个代理层默认加了公共缓存,结果出现了别的用户的数据串号的问题。这属于安全问题,不只是性能优化。所以在做接口缓存规范时,数据类型和安全边界一定要明确。

3.4 如何发现正在发生的“重复传输”

Chrome DevTools 的 Network 面板能直接看到哪些资源是从memory cache、disk cache命中,哪些是200 OK真实传输,哪些是304。但更细致的方法是看“Size”列:如果显示(from disk cache),表示没有网络传输;如果显示(from service worker),说明由 Service Worker 兜底。

我自己常做的一个操作是,在 Network 面板中筛选“资源大小”和“传输大小”。这两个数值的差距能直观反映压缩率。例如一个 JS 文件资源大小是 300KB,传输大小只有 80KB,说明压缩生效了。如果两者几乎一样,你就要怀疑是不是忘了开压缩,或者这个资源本身已经是压缩格式。

对于接口层面的重复传输,我建议在服务端日志里记录每个接口的请求次数、响应大小和调用来源。优化前先统计一遍,就会发现某个列表页 10 分钟内同一个用户请求了同一接口 20 次,而数据根本没有变化。这种时候不要急着加缓存,先问产品经理为什么轮询这么频繁,很多时候是代码里setInterval写错了,甚至组件卸载没有清理定时器。

4. 控制请求的数量与时机:合并、并发与懒加载

4.1 HTTP/1.1 时代的“合并请求”思维,在 HTTP/2 下要重新审视

我刚入行那会,前端优化的金科玉律是“减少请求数”:雪碧图、合并 CSS、合并 JS。这套思路放在 HTTP/1.1 下是对的,因为浏览器对同一域名最多同时建立 6 个左右的 TCP 连接,请求多了就要排队。

但 HTTP/2 普及后,多路复用允许在同一个连接上同时传输多个请求和响应,队头阻塞问题大幅缓解。这时候再盲目把所有 JS 合并成一个 5MB 的超大文件,反而会带来两个坏处:首屏必须等全量代码加载完才能执行;发布时一个文件内容变化,整个缓存都失效。

所以现在做架构方案,我会优先把资源切成合理粒度的多个 chunk,而不是追求“一个文件”。例如:

  • 基础运行库(Vue/React 全家桶)单独一个 vendor chunk;
  • 每个路由页面一个独立 chunk;
  • 公共业务工具一个 shared chunk;
  • 首屏关键路径的资源用 preload 提前加载。

HTTP/2 下的请求数不再稀缺,但也不是无限免费。每个请求仍然有完整 HTTP 头部的开销,单个请求过大同样会拖慢首屏。所以“数量”和“体积”要一起权衡。

4.2 图片懒加载与路由懒加载的落地姿势

图片懒加载能显著减少首屏传输量——但要注意“懒”到什么程度。最简单的是给img标签加loading="lazy",浏览器原生支持。但原生懒加载通常只能做到进入视口附近才开始加载,对于商品列表页够用,对于真正的长列表和滚动流场景,建议用IntersectionObserver自己控制:

const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; observer.unobserve(img); } }); }, { rootMargin: '200px' }); document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img));

像这种方案最好封装成通用指令或组件,避免每个页面复制一套。同时要小心首屏图片的“懒加载反效果”:如果首屏可见区域内的图片也懒加载,会导致加载时机被推迟,实际感知速度反而下降。通常首屏内图片应该预加载,首屏外的才懒加载。

路由懒加载在 2.1 节已经提到了,这里补充一个细节:不要在懒加载路由的 chunk 上再做全量 preload。很多人听说 preload 能提速,就把所有 chunk 都 preload,结果就是所有路由代码都在首屏被下载,懒加载形同虚设。Preload 只应该用于当前页面确定会用到的关键资源。

4.3 预连接和预解析:把“未来的传输”提前准备

DNS 解析、TCP 连接、TLS 握手这些等待时间,可以通过preconnect和dns-prefetch提前完成。比如页面确定会请求api.example.com,可以加:

<link rel="preconnect" href="https://api.example.com"> <link rel="dns-prefetch" href="//api.example.com">

preconnect会提前完成 DNS + TCP + TLS 握手,代价是浏览器会在空闲时占用一个连接。对于未来一定会请求的域名,收益明显。对于第三方统计、字体 CDN 这类可延迟资源,可以用dns-prefetch只提前解析 DNS,成本更低。

我见过过度使用的情况,一个页面写了十几个preconnect,包括未来可能根本不会访问的域名。这样反而浪费移动端宝贵的连接资源。架构上应该有一个“可信域名清单”,只对首屏必须访问的域名开启preconnect。

还有preload和prefetch的区别:preload是当前页面高优先级资源,例如首屏渲染需要的 CSS、字体;prefetch是空闲时提前下载用户“可能”访问的下一个页面资源。Preload 用错了会抢占带宽;Prefetch 用对了可以让下一个页面“秒开”,但也不要一次性 prefetch 太多,否则会消耗用户当月的流量套餐。

5. 内容协商与服务端配合:从接口层面削减传输

5.1 接口返回字段裁剪:能传 20KB,绝不传 300KB

很多时候前端慢不是因为代码多,而是接口返回了一堆用不上的字段。后端一个SELECT *,把整个订单对象所有关联信息都吐出来,前端只在列表里展示五列。这类情况属于典型的“不必要的传输”。

架构上应该建立接口字段最小化规范。比如 REST 接口里增加fields参数,或者把列表接口和详情接口彻底拆开。列表接口只返回 id 和展示列;详情接口按需返回完整对象。

如果项目还在早期,我比较推荐引入 GraphQL 或 JSON:API 这类带字段选择能力的方案。但也要注意,GraphQL 不是银弹。它的优点是把字段选择权交给前端,缺点在于缓存策略更复杂,后端需要处理 N+1 查询和权限控制。对于简单后台系统,用 REST +fields参数足够,没必要为了“先进”而增加复杂度。

我在重构一个报表系统时,把 30 个字段的列表接口裁剪成 8 个字段,接口响应体从 120KB 降到 25KB。配合分页,一页数据只要 3KB。用户切页时体感从“能感觉到加载”变成“几乎瞬时”,这个优化没有改任何页面布局,只动了接口传输协议。

5.2 服务端渲染和数据预取:把多次请求合并成一次

用 Vue 或 React 做纯前端渲染时,页面加载一般要经历:拿到 HTML 壳子 -> 执行 JS -> 请求接口 -> 渲染列表。等于首屏需要一次 HTML 传输,加一次 JS 传输,再加一次接口数据传输,至少三趟网络往返。

服务端渲染(SSR)可以在服务器上直接完成数据查询和组件渲染,输出带内容的 HTML。用户浏览器拿到 HTML 时,首屏内容已经在了,接口请求环节被前置到了服务器内部。这样一来,用户侧少了一次关键请求,体感尤其是弱网环境下会大幅改善。

但 SSR 也有成本:服务器渲染耗时、首屏与二次渲染的数据一致性问题。所以架构师要分场景。纯展示类页面,比如官网首页、文章详情,非常适合 SSR;对交互复杂、依赖浏览器 API 的后台系统,SSR 收益有限且可能让架构复杂度飙升。

更轻量的方案是“数据预取”。在页面构建阶段把首屏接口数据内联到 HTML 的script标签里,前端初始化时直接读取:

<script> window.__INITIAL_STATE__ = { "list": [...] }; </script>

这样用户打开页面时不需要再等接口响应,直接从全局变量里读取数据。这种做法的本质是把原本单独一次请求的传输融入首次 HTML 响应,用“一次传输”替代“两次传输”。

5.3 WebSocket、SSE 和增量更新,什么时候才值得用

接口轮询是“不必要的传输”的重灾区。比如一个订单状态页面,前端每 5 秒调一次接口,用户盯着看 10 分钟不动,数据也没变,白白传输了 120 次请求。

与其轮询,不如用服务器推送。WebSocket 适合双向实时通信,比如在线聊天、协作编辑。SSE(Server-Sent Events)适合单向服务端推送,比如通知、状态更新,且它是标准 HTTP 协议的一部分,浏览器原生支持,比 WebSocket 更轻。

但鼓吹每个项目都升级到 WebSocket 也不现实。我一般会先问两个问题:数据变化频率高吗?用户真的需要实时看到变化吗?如果只是“刷新后能看到最新状态”,用条件请求轮询足够了。加一个If-Modified-Since或ETag,数据没变时返回 304,传输量从全量 JSON 变成几十字节响应头,比 WebSocket 简单得多。

所以这里的原则是:能用条件请求解决的就不要用推送,能用推送解决的就不要高频轮询。

6. 常见问题与排查技巧实录

6.1 现象:用户打开页面白屏,Network 里 HTML 返回 200 但内容是旧的

这个案例是典型的缓存分层设计失误。项目把 index.html 设置成Cache-Control: max-age=86400,同时静态资源用了带哈希的文件名。正常情况下,HTML 变了,文件名会变,用户会拿到新页面并加载新资源。但问题在于,CDN 把 HTML 也缓存了,用户访问的 HTML 永远是昨天那份,而资源文件又没有被缓存或已过期,结果加载了旧 HTML 引用的新资源路径,找不到文件,白屏。

排查时看响应头里 HTML 的cache-control和x-cache-status,一查果然是 CDN 命中。解决方式很简单:HTML 入口文件设置Cache-Control: no-cache,并且发布后主动刷新 CDN 上的 HTML。现在大多数部署平台(如 Nginx + 发布系统)都支持对 HTML 的 “绕过缓存” 规则,一定要在初始架构里就规划好。

这类问题在软考系统架构师的案例题中经常出现,考官想看的往往不是“怎么删缓存”,而是“为什么缓存策略会失败”以及“如何设计一套版本化文件 + 非缓存 HTML 的分层方案”。

6.2 现象:Gzip 已经开启,但某个接口响应体仍然巨大且不被压缩

有一次我们优化一个报表导出接口,明明 Nginx 已经开启了 Gzip,但接口返回的 JSON 数据传输还是 200MB。查到最后发现,后端语言框架里的中间件优先级把Content-Type设成了application/octet-stream,而 Nginx 的gzip_types只匹配了application/json,导致了不压缩。

这类问题很难通过肉眼发现,最好用curl -H "Accept-Encoding: gzip" -I看响应头里有没有Content-Encoding: gzip。如果没有,再逐层排查是网关、负载均衡还是源站没处理对。架构上应该形成一份“压缩链路检查清单”:浏览器是否支持 -> CDN 是否透传 Accept-Encoding -> 源站是否产生压缩 -> 压缩类型是否在允许列表里。

6.3 现象:压缩和缓存都做了,Lighthouse 性能评分还是不高

Lighthouse 里常出现一个提示:“Avoid enormous network payloads”。有些团队做了一堆优化,体积已经降下来了,但评分还是差。原因往往是 3G 模拟和真实网络环境下的缓存命中率不一致。Lighthouse 默认会禁用缓存,所以它能查到所有资源从网络加载——如果你的页面依赖浏览器缓存提高二次访问速度,评分自然会偏低。

这时别只盯着评分,要看优化目标。给团队定性能预算时,我会同时定义一个“首次无缓存加载”和“二次有缓存加载”两个指标。前者考察真实网络传输上界,后者考察缓存设计是否合理。不要因为 Lighthouse 一次跑分不好就推翻整个缓存方案,那是用错了尺子。

6.4 实战排查步骤速查表

步骤操作目的
1打开 Network 面板,开启缓存禁用看最差情况下的传输总量
2勾选“Big requests”和“Slow 3G”模拟定位大头资源和慢请求
3查看每个资源的“Resource Size”和“Transfer Size”判断压缩是否生效,以及是否命中缓存
4在响应头里确认 cache-control / etag / content-encoding直接定位缓存和压缩配置是否正确
5用 WebPageTest 或 Lighthouse 跑分从第三方视角观察关键指标
6拉取服务端访问日志,统计同一用户重复请求频率发现接口轮询和数据重复传输问题

这个表格看起来简单,但真正照着做过一遍的人,基本都能找到至少两三个可以立刻优化的点。大多数“高性能页面”不是靠一个惊艳的大招,而是靠把这些基础步骤打磨到位。

个人经验收尾

做了这么多年前端和架构设计,我越来越觉得“减少不必要的传输”本质上是一种设计理念:每多传一个字节,都要能说出它的用途。这并不是要求前端工程师单纯地压缩文件,而是站在用户网络环境、服务器成本、业务更新频率的整体视角,对每一段传输进行审计。

如果你正准备软考系统架构师,建议把本章内容当成案例题的分析框架,而不只是知识点。考试里问“如何优化前端性能”,能从 HTTP 缓存分层、资源体积压缩、接口字段裁剪、服务端配合这几个维度展开,比只答“上 CDN、开 Gzip”要立体得多。

最后再分享一个小技巧:我每个项目都会准备一份“传输预算清单”,把首次页面加载的字节数、请求数、关键请求耗时贴在团队文档里。每迭代一个版本就跑一遍对比,超了就回滚或者重新讨论。坚持一个季度,你会发现团队对网络传输的敏感度明显提升,这才是这项优化长期有效的关键。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询