先看差异出现在哪一层:用禁用脚本的请求取回的是服务器直接输出的静态HTML,而开启脚本后的结果包含了浏览器执行JavaScript、再发起的数据请求和DOM改写。两者不同,通常不是速度本身变了,而是你比较的其实是两个不同阶段的产物。定位方法是把“脚本执行前”和“脚本执行后”当成两条独立链路分别取样,再判断差异是内容缺失、内容替换,还是时间被推迟。
把两次结果放在一起对比时,先归类,不要急着改代码。常见有三类:
分类不同,下一步动作完全不同。第一类要查数据来源和渲染方式,第二类要查挂载逻辑,第三类才回到常规的资源优化。如果跳过分类直接压测,很容易在错误的方向上反复调参。
判断标准不是“哪种更快”,而是目标内容是否必须依赖运行时数据。
如果目标内容在请求时已经确定,例如文章正文、商品基础信息、栏目列表,那么让服务器直接输出更稳,脚本只负责交互增强。这种情况下差异的根因是渲染位置放错了,改静态输出能同时解决内容缺失和首屏等待两个问题。
如果目标内容依赖用户身份、实时库存、地理位置等运行时条件,静态输出无法预先包含它,那么差异是设计使然。这时要做的不是把内容搬到静态HTML,而是保证静态部分先可用,动态部分延后填充,并确认关键内容不会因为脚本失败而完全消失。
假设一个列表页:静态响应返回了容器和加载占位,脚本请求接口后填入条目。抓取工具在禁用脚本时只看到占位,这就是第一类差异。假设同一页面静态响应已包含前十条条目,脚本执行后根据筛选条件替换成另外十条,这是第二类差异,改动重点在筛选逻辑是否应在服务端完成。这两个例子都说明,先确认内容是否“本来就能确定”,比先测加载时间更有决定意义。
具体做法是固定其他变量,只切换脚本开关,逐项记录。
第5步是关键动作:它把“脚本渲染”这个大概念收窄到具体数据依赖。确认依赖后,下一步要么把数据在服务端预取并写入HTML,要么接受它必须运行时加载并调整对静态响应的预期。如果不做这一步,你无法区分是渲染方式问题还是接口本身返回慢。
有几种情况会让对比结论失真,需要单独排除。
一是缓存。两次请求可能命中不同缓存层,导致你以为是脚本造成的差异,实际是缓存版本不同。复测时应确保两次取样在同等缓存条件下进行。
二是脚本报错。脚本执行中断会让DOM停在中间状态,看起来像内容缺失,实际是错误导致。查看控制台错误比继续对比内容更快定位。
三是延迟加载。内容确实在静态响应里,但被脚本在滚动或空闲时才插入。禁用脚本时看不到,不代表服务器没输出。检查原始HTML源码而不是渲染后的可见区域,可以避免这个误判。
四是抓取限制与索引的混淆。robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录。如果差异是在抓取工具里观察到的,先确认限制规则是否影响了取样本身,再谈渲染差异。
另外,请求量或抓取量某项指标归零,不能单独证明你的判断正确。它也可能是取样时段、工具配置或访问路径变化造成的,需要结合响应内容一起看。
定位这类差异的核心动作只有一个:在同等条件下分别保存静态响应和脚本渲染后的DOM,然后判断目标内容是新增、替换还是仅被推迟。新增指向渲染位置,替换指向挂载逻辑,推迟指向资源加载。做完这个判断,再决定是把内容前移到服务端输出,还是保留运行时渲染但补上静态兜底。选择依据始终是内容在请求时能否确定,而不是哪种方式看起来更快。