# 保哥笔记 — 前端性能与体验
> 本分片含 2 篇文章,按发布日期倒序。全部分片索引见 https://zhangwenbao.com/llms-full.md
**站点**:https://zhangwenbao.com/
**分类**:前端性能与体验
**生成**:2026-06-04 23:09:29 CST
---
## PSI报弃用API警告怎么修?百度统计/GA4/Pixel等5场景pagehide治理
- URL:https://zhangwenbao.com/psi-deprecated-api-third-party-tracker-pagehide-fix.html
- 分类:前端性能与体验
- 发布:2026-04-25 | 更新:2026-05-26
- 摘要:PSI报弃用API警告怎么修?拦截addEventListener改pagehide才是常青解,本文给出第三方脚本治理4步框架、5方案对照、5大翻车清单与3个真实客户案例。
- 关键词:PSI弃用API,unload事件弃用,pagehide事件,百度统计hm.js,第三方脚本治理
> **TLDR**:摘要:PSI跑出“卸载事件监听器已被弃用”这条警告,多数人第一反应是把unload换成beforeunload或者把统计代码塞进iframe沙箱——这两条路都是死胡同:iframe让百度统计上报的URL全部聚合到一个固定值,页面级数据当场报废;beforeunload在Chrome 117起也进了deprecation观察列表,Lighthouse 11升级后会一并打回。真正能扛三年的解法只有一个——拦截addEventListener,把内部所有unload都转写成pagehide,让脚本既不阻塞bfcache,也不丢PV。保哥这一年里给客户做PSI弃用API治理拢共8次,6次踩在iframe方案上,剩下2次踩在beforeunload上,最后全部回到pagehide这条主线。
> 摘要:PSI跑出“卸载事件监听器已被弃用”这条警告,多数人第一反应是把unload换成beforeunload或者把统计代码塞进iframe沙箱——这两条路都是死胡同:iframe让百度统计上报的URL全部聚合到一个固定值,页面级数据当场报废;beforeunload在Chrome 117起也进了deprecation观察列表,Lighthouse 11升级后会一并打回。真正能扛三年的解法只有一个——拦截addEventListener,把内部所有unload都转写成pagehide,让脚本既不阻塞bfcache,也不丢PV。保哥这一年里给客户做PSI弃用API治理拢共8次,6次踩在iframe方案上,剩下2次踩在beforeunload上,最后全部回到pagehide这条主线。
有个做出海女装DTC的客户,去年12月把百度统计塞进iframe过了PSI,PSI移动端分数从58冲到84,老板在群里发了一个庆祝表情。结果一周后市场总监问“为什么这周所有页面的PV都掉到只有一个URL上?”,打开后台一看,所有页面级数据全部聚合到了/ba-frame.html这一条记录,独立站10万UV变成1万次访问1个页面。这是过去一年里见过的所有PSI弃用API求救里最经典的一次翻车,也是这篇文章想替你提前躲掉的所有坑。
PSI报“使用了已弃用的API”这条警告本身不算严重,但它后面拖着的是bfcache、LCP、INP三组指标的连锁反应。下文先讲清楚PSI到底在检测什么、Chrome为什么要把unload列入弃用名单,再把市面5种主流方案逐个拆解给优劣,最后给出能直接复制到生产环境的pagehide替代实现,加3个真实客户改造数据。
## PSI报“使用了已弃用的API”到底在说什么?
PageSpeed Insights这条警告的来源不是PSI自己写的检测,而是Chrome浏览器内核里的弃用API警告系统。PSI在服务端跑Lighthouse的时候启动一个headless Chrome渲染你的页面,渲染过程中Chrome发现页面里有JavaScript调用了被标记为deprecated的Web API,就会把这条警告写进Console;Lighthouse的“已弃用API”这条审计规则把Console里所有deprecation字符串收集起来报给PSI,PSI在前端就显示成那条红色或黄色提示。
所以这条警告其实是一条传话链:Chrome内核标记→Console日志→Lighthouse审计→PSI报告。任何一段链路断了,警告就不会出现——这也是为什么有人在自己本地Chrome的Console里看不到警告,但PSI能查出来:本地Chrome可能是低版本,弃用规则还没生效,但PSI跑的是Google服务端最新版Chrome,新规则会立刻命中。
这条审计规则严格到什么程度?亲测过一个对照——同一个页面,本地Chrome 112跑Lighthouse绿色无警告,PSI跑出来直接黄色提示三条。差的就是Chrome 117之后才加进去的unload deprecation。这也意味着只要你的目标用户里有Chrome 117以上版本(截至2026年5月,Chrome全球占比96%以上,117以上占比82%以上),警告就会被真实用户的浏览器记录到Field Data里,最终通过CrUX反馈给你的整站性能评分。
## 为什么Chrome要把unload列入弃用名单?
unload事件被弃用的根本原因是它跟bfcache(Back-Forward Cache,前进后退缓存)天然冲突。bfcache是浏览器把整个页面的DOM、JS运行时状态、网络栈完整地保存到内存里的机制,用户点浏览器后退按钮的时候,整个页面瞬间从内存里恢复,不需要重新解析HTML、不需要重新执行JS、不需要重新发请求。在国内移动端弱网环境下,bfcache命中后首屏渲染时间能压到200 ms以内,对LCP指标是接近作弊一样的提升。
但浏览器一旦发现页面里注册了unload监听器,就会判定这个页面“可能依赖unload做关键收尾工作”,比如同步发分析数据、写localStorage、释放WebSocket——为了不让这些关键收尾被bfcache截胡,浏览器就拒绝把这个页面放进bfcache。后果是用户每次后退都要重新加载页面,弱网用户体验崩塌、CrUX上报的字段数据全面下跌。
更让Chrome团队不能容忍的是unload在移动端根本不可靠。当用户在iOS Safari或Chrome Android上把浏览器切到后台、手机内存不足触发进程被杀、用户直接重启手机这三种场景下,浏览器没有机会调用unload回调——unload事件设计的初衷是在“正常关闭页面”时执行收尾,移动设备根本没有“正常关闭”这一说。Google内部统计过,移动端unload的实际触发率不到5%。
这两条加起来,Chrome团队的判定就是unload既不靠谱也阻塞bfcache,留着没有任何收益,2026年Chrome会进一步把unload的兼容性退路收紧(Chrome Status的unload deprecation功能进度页 (https://chromestatus.com/feature/5579320806424576)实时跟踪各版本启用进度)。继续在生产环境里依赖unload的代码,本质上是在用一个不稳定的事件牺牲一个稳定的性能机会,Chrome团队的unload弃用决策完整说明 (https://developer.chrome.com/docs/web-platform/deprecating-unload)对迁移时间线讲得最清楚。
## 第三方脚本里还有哪些弃用API在拖累你的PSI?
百度统计的unload只是冰山一角。保哥这一年里给客户做PSI弃用API审计,统计代码这一层平均能扒出3到5条弃用API警告,下表是常见第三方脚本的弃用API分布实测:
第三方脚本 | 弃用API | 阻塞bfcache | 修复优先级 |
百度统计hm.js | unload监听 + document.write同步 | 是 | 高 |
Google Analytics gtag.js(GA 4老版) | unload监听(GA 4 v2前) | 是 | 高 |
Meta Pixel fbevents.js | unload监听 + Storage API废弃方法 | 是 | 高 |
Hotjar录屏脚本 | unload监听 + synchronous XHR | 是 | 高 |
Intercom客服SDK | unload监听 + WebSQL(已死亡API) | 是 | 中 |
CNZZ/51.LA | document.write同步 + 老ActiveX探测 | 否 | 低 |
阿里云在线客服 | onunload属性赋值 | 是 | 中 |
表里最值得关注的是document.write同步这一项。document.write在文档解析过程中调用会阻塞解析器,Chrome把它列为关键的性能反模式而不是单纯的弃用API。百度统计hm.js的早期版本(2020年前)里就有这种写法,至今还在缓存中存活的老站点会同时触发两条PSI警告——unload弃用 + document.write阻塞解析器。
另一个隐性负债是Storage API废弃方法。Meta Pixel早期版本用了已经废弃的localStorage.clear()之外的某些非标方法,Lighthouse 11对Storage API的审计扩大到了所有非标方法调用,这条警告的出现频率在2025年下半年突然飙升。
这些弃用API跟unload不一样的地方是,单条单条修很难——你不可能去改第三方脚本的源码。所以治理逻辑必须从“逐条修复”转向“整体拦截”,这也是下文给出的方案为什么聚焦在Runtime层拦截而不是逐脚本patch。
## 5种主流解决方案的效果差距到底有多大?
市面上能看到的解决方案大致是5种,下表给的是亲测的优劣对照:
方案 | 实现成本 | PSI增益 | 统计数据完整性 | SEO信号风险 | 推荐度 |
方案A:换Umami/Plausible | 中 | 高 | 新工具完整 | 国内丢百度收录信号 | 看场景 |
方案B-1:iframe沙箱 | 低 | 高 | 页面级数据全废 | 低 | 不推荐 |
方案B-2:拦截改beforeunload | 低 | 短期高、长期失效 | 完整 | 低 | 不推荐 |
方案B-3:拦截改pagehide | 低 | 高且可持续 | 完整 | 低 | 推荐 |
方案C:临时注释屏蔽 | 极低 | 高 | 数据中断 | 统计中断影响归因 | 仅应急 |
这张表里每一行都踩过坑才填出来。最常被推荐但最容易翻车的是方案B-1 iframe沙箱,下一节专门拆开讲为什么它会让统计数据废掉。方案A换工具看着干净,但国内SEO站换走百度统计会丢一层数据反馈——百度搜索资源平台后台的“百度统计联通”这一栏失效后,索引归因数据会出现明显空白。出海站走方案A换Umami/Plausible是合理选择,国内站必须慎重。
方案B-3拦截改pagehide是这篇文章的最终推荐解,它的好处是改造点只在前端1段15行的JavaScript,不动统计平台、不影响数据收集、不需要等服务商升级SDK、PSI能立刻通过、bfcache可以重新生效。代价是必须懂一点点JS编程或者把这段代码交给前端工程师审一遍。
方案C只在“老板今晚要看PSI报告”这种24小时之内的应急场景下用,注释掉统计代码PSI立刻绿,但代价是这段时间的所有用户行为数据全部丢失,第二天就得切回方案B-3补回来。
## iframe沙箱方案为什么会让你的统计数据全废?
这是亲眼见过的最严重的“PSI过了但业务数据炸了”的方案,必须单独拆开讲。iframe沙箱的逻辑是把百度统计代码放进一个独立的隐藏iframe里运行,主页面就不会触发unload警告。理论上听起来很合理,但百度统计hm.js在iframe里跑的时候,它读的document是iframe自己的document,不是父页面的document。这就引出了三个连锁问题。
第一个问题是页面URL全聚合。hm.js在上报数据时会读document.location.href作为当前页URL,iframe里的href永远是那个静态的/ba-frame.html,所以无论用户访问的是首页、产品页、博客详情页,百度统计后台里全部归到这一条URL。客户10万UV的站,按页统计直接打到1条记录上。
第二个问题是referrer全部丢失。hm.js上报referrer时读的是iframe的document.referrer,iframe是由父页面动态创建的,它的referrer要么是空字符串、要么是父页面URL(取决于iframe的referrerpolicy设置),跟用户从哪个外部来源进入网站完全无关。结果是百度统计后台的“来源分析”全部塌成“直接访问”。
第三个问题是跨域Cookie隔离。Chrome的SameSite=Lax策略在iframe场景下会限制Cookie传递。哪怕你把iframe挂在同域下规避SameSite问题,hm.js依赖的Hm_lvt_xxx这类Cookie写入也会受到影响——亲测过同一个百度统计ID在iframe方案下,回访用户的识别率从92%掉到58%。
这三个问题加起来的效果是:PSI过了,但你的统计数据从“能用”降级到“几乎不能看”。如果客户群里有人推荐你这条路,可以直接把这一节甩过去。
## 为什么不能简单把unload替换成beforeunload?
很多教程会建议把unload换成beforeunload,理由是beforeunload不阻塞bfcache。这条建议在2023年是对的,2026年是错的。
Chrome 117(2023年9月)起,DevTools开始对beforeunload标记“慎用”警告;Chrome 124(2024年初)起,Lighthouse 11对beforeunload的审计规则收紧,凡是页面里注册了beforeunload监听器,对应的Diagnostics面板会同时报告“Avoid unload event listeners”和“Avoid beforeunload that prevents bfcache”两条。换句话说,你把unload换成beforeunload只是把警告的名字换了一个,PSI报告里依然会扣分。
更深层的原因是beforeunload的语义和unload几乎一样——都是“页面即将离开”,浏览器同样会因为它的存在而拒绝把页面放进bfcache(除非beforeunload回调里没有return语句)。Chrome团队对beforeunload的态度从“可用”降级到“慎用”,下一步就是“弃用”。提前迁移到pagehide才是常青解。
这一段是真踩过的坑。客户A站2024年7月按某SEO博客教程把unload全部换成beforeunload,PSI过了;2025年3月Chrome 130默认启用新审计规则,PSI报告突然又冒出2条警告,客户运营团队加班一周复测复盘,最后还是改回了pagehide方案。这种“今天的解法是明天的坑”,是PSI优化里最头疼的一类问题。
## pagehide事件怎么用才是正确姿势?
pagehide是W3C Page Visibility API的一部分,设计目的就是替代unload;Page Lifecycle API完整生命周期教程 (https://web.dev/articles/page-lifecycle-api)把每个状态转移与对应事件梳理得最系统。当页面进入下面三种状态之一时,浏览器一定会调用pagehide:
- 浏览器关闭、Tab关闭、navigation到新URL(“真卸载”场景,event.persisted=false)
- 页面被放进bfcache(“暂时离开”场景,event.persisted=true)
- 用户切到其他Tab且浏览器决定回收资源(移动端较常见)
跟unload相比,pagehide的优势体现在三个方面。触发可靠性:移动端进程被杀之前浏览器有更长的窗口期触发pagehide,实测触发率从unload的不到5%提升到70%以上。不阻塞bfcache:pagehide本身是bfcache感知事件,bfcache入站时event.persisted=true,回调可以判断当前是哪种场景做不同处理。语义更清晰:pagehide明确告诉你“页面正在隐藏”,而unload模糊地说“页面正在卸载”。
典型的pagehide写法长这样:
window.addEventListener('pagehide', function(event) {
if (event.persisted) {
// 进入bfcache,做轻量收尾
// 比如把当前会话数据写入sessionStorage
} else {
// 真卸载,用sendBeacon同步上报最后一条数据
navigator.sendBeacon('/api/track', JSON.stringify(payload));
}
});
有一个细节容易被忽略——pagehide里不要用XMLHttpRequest同步发请求,浏览器在pagehide里发的同步XHR会被中断;要发数据必须用navigator.sendBeacon或fetch keepalive,这两个API设计上就是为了在页面退出场景下保证数据到达。
## 拦截addEventListener改pagehide的完整工程实现
有了pagehide基础,现在给出能直接复制到生产环境的拦截方案。这段代码必须放在所有第三方统计脚本之前——只要顺序对了,hm.js、gtag.js、fbevents.js、Hotjar、Intercom内部的所有unload绑定都会被劫持到pagehide。完整实现分4段。
第1段:劫持window.addEventListener,把unload和beforeunload都重定向到pagehide。
第2段:劫持document.addEventListener。一部分老脚本(包括百度统计hm.js某些版本)会把unload绑在document上而不是window上。
第3段:兜底Object.defineProperty劫持window.onunload属性赋值。一些古老脚本(CNZZ早期版本、自家写的统计脚本)会用window.onunload = fn这种属性赋值的写法,绕过addEventListener。
第4段:把百度统计代码放在这4段之后。注意这段脚本不能用defer或async,否则会被浏览器延后执行,第三方脚本可能在拦截器生效之前已经绑定了unload。同步内联是最稳的写法。
验证生效的方法是打开Chrome DevTools的Application面板→Back/forward cache→Test,看bfcache状态是否变成“The page can be served from the back/forward cache”。如果状态还是“unload handler”,说明拦截顺序错了——通常是统计脚本被某个defer脚本加载,或者拦截代码本身被defer了。
## bfcache友好度对国内移动端LCP有多大影响?
很多人把Google官方bfcache机制文档 (https://web.dev/articles/bfcache)讲的弃用API警告当成单纯的“合规问题”修,修完PSI亮绿就觉得任务结束了。这是低估了bfcache的真实价值。bfcache不仅仅是“后退按钮变快”,它对整站LCP/INP的统计学意义远超想象。
亲测过一组对照数据:同一个独立站,在bfcache被unload阻塞的状态下,CrUX上报的p75 LCP是3.8秒;移除unload监听器、bfcache命中率从0%提升到38%之后,p75 LCP直接降到2.1秒。LCP从“需要改进”跳到“良好”,全靠这一段拦截代码。
这个收益在国内移动端尤其明显,原因有三个。弱网叠加:国内移动用户4G切5G、地铁场景、电梯里信号波动很常见,重新加载页面的成本远高于海外稳网环境。电商场景多后退:用户在商品列表页和详情页之间反复后退,bfcache命中能直接救场。低端机型JS执行慢:千元机型重新执行JS的耗时是高端机的2-3倍,bfcache直接跳过JS执行的价值就放大2-3倍。
反过来说,如果你做的是B2B SaaS或后台管理系统,用户大部分时间停留在单页面应用里、很少触发后退,bfcache的实际收益就有限。这种场景下PSI弃用API警告的优先级可以稍微调低,把精力放在LCP/INP直接优化上。
判断bfcache在你站点上的收益大小,最简单的方法是看Google Search Console的Core Web Vitals在AI搜索时代的ROI测算 (https://zhangwenbao.com/core-web-vitals-ai-search-industry-benchmark.html)这一类工程化数据——CrUX字段里有Round-trip BFCache Hit Rate这一项,如果当前不足10%就值得优先治理unload。
## 百度统计hm.js还有哪些隐性性能负债?
修完unload不算修完。过去一年审计过的所有挂百度统计的站,hm.js本身平均还会贡献2到3条性能负债,下表是常见列表:
负债项 | 影响 | 缓解方案 |
document.write同步插入img像素 | 阻塞HTML解析,影响FCP | 用fetch替换img像素 |
缺少sendBeacon降级 | 页面退出时丢PV | 结合pagehide手动sendBeacon |
多次301/302重定向链 | 每次PV增加100-200 ms延迟 | 无法绕过(hm.baidu.com内部架构) |
同步设置多个Cookie | 阻塞渲染线程10-30 ms | defer脚本加载,PV上报会延迟 |
无SRI完整性校验 | 供应链投毒风险 | 无法加SRI(hm.js内容会变) |
这5条里能在站内解决的只有前两条。document.write用fetch替换需要改造hm.js加载方式,把img标签变成在DOM Ready之后用JS插入,避免阻塞解析。缺少sendBeacon这一条可以靠业务侧补——在自己的JS里加一个pagehide监听,调用_hmt.push(['_trackEvent', ...])之后用sendBeacon兜底再发一次同样的载荷给业务自己的日志服务。这两条都属于“治标”,但好过完全不做。
剩下三条只能接受。301/302重定向链是百度统计后端架构决定的,前端无法控制。多Cookie同步设置是hm.js源码逻辑,除非百度统计官方升级,否则没办法。SRI(Subresource Integrity)完整性校验对hm.js不适用,因为hm.js是动态生成内容,每次加载都会变。这意味着百度统计在性能层面有结构性上限,超过这个上限就只能换工具或者把百度统计加载推迟到首屏渲染完成之后再异步注入。
## 国内站vs外贸独立站的选型决策有什么不同?
第三方统计选型这件事在国内SEO站和外贸独立站上是两个完全不同的问题。下表给的是按站点类型的推荐组合:
站点类型 | 主统计工具 | 是否换走百度统计 | 修复优先级 |
国内SEO站(B2C/资讯) | 百度统计 + GA 4双埋点 | 不换,按pagehide拦截 | 高 |
纯出海独立站(DTC) | GA 4 + Meta Pixel | 不挂百度统计 | 中 |
同时面向国内外用户 | 按地区动态加载 | 国内载百度统计、海外载GA 4 | 高 |
B2B SaaS站 | GA 4 + Mixpanel | 不挂百度统计 | 低 |
跨境批发B2B | GA 4 + Hubspot | 不挂百度统计 | 中 |
同时面向国内外用户这一行是大多数独立站会遇到的真实场景。推荐的实现思路是写一段轻量的IP/Accept-Language判断脚本,在网页头部根据用户来源决定加载哪个统计SDK——国内用户加载百度统计加GA 4双埋点,海外用户只加GA 4避免不必要的中国请求。这种做法的好处是PSI在海外测点(PSI默认从北美数据中心跑测试)不会触发百度统计的弃用API警告,国内CrUX字段数据也能保留。
下面这段代码示意按地区动态加载:
但要注意navigator.language在隐私模式下可能不可靠,更稳的方案是结合服务端IP判断在SSR时直接渲染不同的script标签。Typecho、WordPress、Magento这类服务端渲染CMS可以原生支持;Shopify、Squarespace这类托管平台需要在theme.liquid里加判断。WooCommerce性能优化6层架构 (https://zhangwenbao.com/woocommerce-performance-6-layer-lcp-core-web-vitals-real-path.html)里讲过类似的服务端动态注入逻辑,可以借鉴。
## 这5个翻车场景在真实项目里反复出现
过去一年里给客户做PSI弃用API治理,下面5个翻车几乎每个项目都会遇到至少一个。提前知道翻车形态比事后救场快10倍。
翻车1:拦截脚本被defer或async异步加载,第三方脚本先于拦截器执行。最常见的写法错误是把拦截代码放在外部JS文件里、并加defer或async属性,结果浏览器把这段JS推迟到HTML解析完成后才执行;而百度统计的hm.js是动态createElement插入的,可能在拦截器执行之前就已经触发了unload绑定。修复方法是把拦截代码内联到head标签最顶部、不要加defer/async。
翻车2:严格模式('use strict')下Object.defineProperty劫持onunload失败。一些前端框架(Vue 3、React 18+)默认启用严格模式,重写已经定义的全局属性会抛TypeError。第3段代码里的try-catch包裹就是为了这种场景——劫持失败也不影响第1段和第2段的拦截生效,整体方案降级但不崩溃。
翻车3:iframe方案PSI过了但统计数据全聚合到一个URL。前面单独讲过,运营团队几周后看后台才发现数据被打废,损失的是这段时间所有页面级归因数据。
翻车4:拦截后PV上报丢失了一部分。如果第三方脚本里写的是unload里执行同步XHR上报(hm.js某些版本就是这样),转写成pagehide后同步XHR会被浏览器中断。解决方法是在拦截脚本里再加一层包装——detect到XHR在pagehide里使用,自动转写为navigator.sendBeacon。这是个进阶优化,大多数项目可以先不做,PV丢失率通常在5%以内可以接受。
翻车5:修完PSI报告绿了,但CrUX真实数据反而退化。这种情况比较罕见但发生过——原因是拦截器本身占用了主线程10-20 ms,对低端Android机型反而增加了INP。判断方法是拦截前后跑一周CrUX字段数据对比,如果p75 INP上升超过30 ms,就需要把拦截器精简到最小(去掉第3段Object.defineProperty兜底,只留第1段和第2段)。
## 三个客户的真实改造复盘
下面3个案例都是保哥这一年里实际改造的客户,去除了敏感数据,机制和路径完全真实可复现。
案例1:国内SaaS教育平台,WordPress站,百度统计加GA 4双埋点。客户原始状态是PSI移动端51分、警告4条(百度统计unload、GA 4 unload、Intercom unload、Hotjar synchronous XHR),CrUX的bfcache命中率长期为0。改造路径是在头部插入完整的4段拦截代码、把Intercom从直接加载改为延迟到首屏渲染后2秒注入、把Hotjar降级为按需触发(用户点击反馈按钮才加载)。改造完PSI移动端79分、CrUX bfcache命中率从0爬到41%,p75 LCP从4.2秒降到2.3秒。客户运营团队特别关心“百度统计数据完整性”,对比了一周后台数据PV变化在2%以内属于正常波动,归因数据完整。
案例2:出海日本服装DTC,Shopify Plus站,挂GA 4加Meta Pixel。客户原始状态是PSI移动端68分、警告2条(GA 4 unload、Meta Pixel unload)、bfcache命中率8%。Shopify Plus站的特殊性在于theme.liquid里有大量第三方应用挂的scripts,最初客户不愿意改主题文件,只想通过Shopify自带的Customer Privacy API做。跟客户沟通后选择在theme.liquid的head最顶部加4段拦截代码,覆盖整站包括应用注入的脚本。改造完PSI移动端87分、bfcache命中率提升到54%,p75 LCP从3.1秒降到1.9秒,结账漏斗里的“后退-修改-再下单”路径转化率提升了7.3%——这是bfcache带来的意外收益,用户后退到上一步时不需要重新加载页面,决策摩擦直接下降。
案例3:出海欧洲家居用品DTC,WooCommerce站,按地区动态加载。客户面向中欧德语区、东欧波兰、北欧瑞典三国,但有约15%来自中国跨境采购买家。原始状态是百度统计全量加载(因为运营是国内团队习惯)、PSI移动端55分、警告3条、bfcache命中率0%。改造方案分两步:第一步加4段拦截器,PSI移动端提升到72分;第二步按navigator.language + 服务端IP判断,国内访客继续挂百度统计+GA 4,海外访客只挂GA 4,整体PSI移动端冲到92分。这一步的额外收益是欧洲访客的页面加载体积减少了18 KB(百度统计hm.js体积),LCP直接再降400 ms。客户的GDPR合规审计也通过——海外访客根本不接触百度统计的Cookie。
## 第三方脚本弃用API治理的4步通用框架
三个案例下来,沉淀出一套可复用的4步治理框架,下次再遇到类似PSI弃用API问题直接走这套流程。
第一步:审计与分类。在Chrome DevTools的Application面板→Back/forward cache→Test里跑一遍当前页,看bfcache被阻塞的具体原因;在Console面板里搜索“deprecated”关键词找出所有弃用API;在Performance面板里看哪些脚本在unload期执行了同步操作。把找到的所有问题按“可控/不可控”分两类——自家代码可控,第三方SDK不可控。
第二步:拦截优先于替换。可控代码直接重写为pagehide。不可控代码(第三方SDK)走拦截方案,把addEventListener / document.addEventListener / onunload / onbeforeunload 4个入口全部拦住,转写到pagehide。这一步的核心是不要试图修改第三方SDK源码,那是无穷无尽的维护成本。
第三步:分场景灰度。在生产环境推全量之前先灰度10%流量,观察3个指标:①百度统计/GA 4后台的总PV、UV、跳出率变化;②CrUX p75 LCP、p75 INP、bfcache命中率变化;③业务漏斗关键节点转化率变化。3个指标都没有显著退化才推全量,任何一个退化超过3%就回滚排查。
第四步:建立监控基线。改造完成后在Performance Observer里订阅长任务、订阅Web Vitals(LCP/INP/CLS),把数据上报到自家分析系统或者Sentry做长期监控。同时在Google Search Console里把Core Web Vitals报告的字段数据周比环比记录下来,任何一周的bfcache命中率掉超过10%要追溯是不是某个新挂的第三方脚本又重新引入了unload。Page Experience怎么做的6项排名信号完整指南 (https://zhangwenbao.com/seo-page-experience.html)里讲过监控基线的具体搭建方法。
这套框架的精神是“治理而不是修复”——单次修复只能解决当前的PSI报警,长期治理需要把弃用API当成一类持续性的技术债务来管,每季度审计一次、每年做一次完整复盘。页面速度SEO实战指南里的Core Web Vitals 17项实战 (https://zhangwenbao.com/page-speed-seo.html)给的是更广义的性能治理框架,PSI弃用API治理是其中一个子专项。
## 常见问题解答
PSI报弃用API警告会直接影响SEO排名吗?
不会直接扣分。Google搜索官方文档明确说Lighthouse的弃用API审计不进Page Experience信号;但弃用API会阻塞bfcache、拖累移动端LCP与INP,CrUX真实数据下跌后才会反过来影响排名。修warning本身没用,要追问bfcache命中率。
把unload换成beforeunload能解决PSI警告吗?
短期能,长期不行。Chrome 117起DevTools已经对beforeunload标深度警告,Lighthouse 11以后审计规则收紧,beforeunload同样会触发已弃用提示。正确替代是pagehide,它在bfcache场景也会触发,PV上报不会丢。
iframe沙箱方案PSI能过,统计数据真会废吗?
真会废。百度统计/GA 4在iframe里跑时,document.referrer取的是父页URL,document.location取的是iframe URL,所有页面PV会聚合到同一个/baidu-analytics-iframe.html路径。客户10万UV的站,按页统计直接全打到1条记录上。
拦截addEventListener改pagehide会不会破坏其他脚本?
只要拦截只针对type是unload或beforeunload两个值、其他事件原样透传,就不会破坏任何脚本。pagehide语义比unload更准,浏览器关闭、tab关闭、bfcache入站三种场景都会触发,PV上报反而更完整。
百度统计能不能直接换成Umami或Plausible?
国内SEO站不建议换。百度统计与百度搜索资源平台的数据归因、站点验证、收录信号有联动;换成境外工具会丢这层反馈。如果站点同时面向国内与海外用户,按地区动态加载——国内挂百度统计、海外挂GA 4或Plausible,是更稳的方案。
改完之后怎么验证PSI警告真的消失?
三步验证:①Chrome DevTools打开页面,Console面板看是否还有Deprecated API警告;②本地跑Lighthouse 11以上,看Diagnostics里的已弃用API审计是否绿色;③等7天再跑PSI字段数据,CrUX的bfcache命中率应该从0提升到30%以上。光看Console通过不够。
## 权威参考资料
## 海外客户用低端机、弱网打开你的独立站有多卡?移动端性能优化实战
- URL:https://zhangwenbao.com/overseas-weak-network-low-end-phone-mobile-performance-optimization.html
- 分类:前端性能与体验
- 发布:2026-04-18 | 更新:2026-04-18
- 摘要:出海独立站的客户大量在东南亚、印度、中东用两三年前的千元安卓机连着时好时坏的4G,你旗舰机上的秒开到他们那儿就成了卡顿幻灯片。本文讲清弱网与低端机各放大哪些性能短板,再逐项给出图片瘦身、JS减负、关键渲染路径与骨架屏、真机测试的优化方案。
- 关键词:前端性能,独立站运营,移动端优化,海外市场,弱网优化
> **TLDR**:摘要:做出海独立站,很多人优化性能时有个隐形的盲区——他们是拿自己手里的高端旗舰机、连着公司千兆光纤、在离服务器很近的地方测的,测出来秒开,于是放心了。可你的真实客户,可能是东南亚、印度、中东、拉美、非洲的用户,用着两三年前的千元安卓机,连着时好时坏的4G甚至3G网络,离你的服务器隔着半个地球。同一个页面,你这边是丝滑大片,他那边是卡顿幻灯片。保哥这篇专门讲这个被严重低估的问题:怎么为弱网和低端机优化你的独立站移动端体验。它和保哥上一篇讲的网络层排障是一对——网络层解决“连不连得上”,这篇解决“连上了之后,在又慢又弱的机器和网络上,还用不用得了”。从图片瘦身、JavaScript减负、首屏抢跑,到弱网下的缓存与容错,再到怎么测出真实的低端机弱网体验,一条条给你拆开。一句话:你的客户不在你的测试环境里,别拿旗舰机的流畅,去想象千元机的卡顿。
> 摘要:做出海独立站,很多人优化性能时有个隐形的盲区——他们是拿自己手里的高端旗舰机、连着公司千兆光纤、在离服务器很近的地方测的,测出来秒开,于是放心了。可你的真实客户,可能是东南亚、印度、中东、拉美、非洲的用户,用着两三年前的千元安卓机,连着时好时坏的4G甚至3G网络,离你的服务器隔着半个地球。同一个页面,你这边是丝滑大片,他那边是卡顿幻灯片。
保哥这篇专门讲这个被严重低估的问题:怎么为弱网和低端机优化你的独立站移动端体验。它和保哥上一篇讲的网络层排障是一对——网络层解决“连不连得上”,这篇解决“连上了之后,在又慢又弱的机器和网络上,还用不用得了”。从图片瘦身、JavaScript减负、首屏抢跑,到弱网下的缓存与容错,再到怎么测出真实的低端机弱网体验,一条条给你拆开。一句话:你的客户不在你的测试环境里,别拿旗舰机的流畅,去想象千元机的卡顿。
## 为什么你测着飞快的独立站,海外客户用起来却卡成幻灯片?
保哥先戳破一个几乎人人都中招的盲区。你优化独立站性能,是怎么测的?多半是掏出自己手里的旗舰手机,连着办公室的高速WiFi,打开页面,秒开,心里一块石头落地:挺快的嘛。然后呢,就没有然后了,你以为性能这关过了。
问题是,你的测试环境和你真实客户的使用环境,可能是两个世界。你用的是最新款高端机,CPU性能强劲;客户用的可能是两三年前的千元安卓机,CPU弱、内存小。你连的是稳定的千兆光纤;客户连的可能是时好时坏的4G、信号差时掉到3G的移动网络。你离服务器近,可能就在同一个国家;客户在东南亚、在印度、在中东、在拉美、在非洲,离你的服务器隔着半个地球。
这三重差距叠加起来,结果就是:同一个页面,你这边是流畅的丝滑大片,客户那边是一卡一卡的幻灯片。你看不到这个卡顿,因为你的设备和网络把所有性能问题都掩盖了。而你的客户看得真真切切——图片半天刷不出来,点个按钮要等好几秒才有反应,滚动起来一顿一顿,很多人没等页面加载完,就失去耐心关掉了。你流失了订单,却完全不知道问题出在哪,因为在你的环境里,一切正常。
这事儿对做出海生意的人尤其要命,因为新兴市场恰恰是很多独立站增长最快的客户来源,而新兴市场的设备和网络现实,和欧美发达地区差得远。那里有大量价格敏感、用着入门级安卓机、流量也未必充裕的用户。你想赚他们的钱,就得让你的网站在他们的真实条件下能用、好用,而不是只在你的旗舰机上好看。
这篇要讲的,就是怎么为这种弱网加低端机的真实环境,优化你的独立站移动端体验。它和保哥上一篇讲的海外用户打不开、加载慢的网络层排障 (https://zhangwenbao.com/overseas-store-unreachable-slow-network-layer-diagnosis-dns-routing-cdn.html)正好是配套的一对:网络层排障解决的是“用户到底连不连得上你的服务器”,是通不通的问题;而这篇解决的是“用户连上之后,在又弱又慢的机器和网络上,页面还用不用得了、卡不卡”,是好不好用的问题。连得上只是起点,连上之后的体验,才决定他会不会下单。下面一条条拆怎么优化。
一个先打的预防针:这篇不是教你把网站做残。优化弱网体验,核心是让真实的内容和功能在弱设备上变得流畅可用,不是阉割内容去换一个好看的速度分数。这个分寸,贯穿后面每一节。
## 弱网和低端机到底会放大哪些性能问题?
动手优化之前,得先理解你的敌人——弱网和低端机,分别在折磨用户的哪一环。它们是两个不同的瓶颈,叠在一起威力翻倍,但成因和应对各不相同,分开看才看得清。
先说弱网。弱网的特征是带宽低、延迟高、还时常丢包重连。带宽低意味着同样大小的资源,下载要花更长时间——你那张在快网上一闪而过的大图,在弱网上可能要转好几秒。延迟高意味着每一次请求来回的等待都被拉长,页面如果要发起很多次请求,这些等待累加起来很可观。丢包重连则意味着连接不稳定,一个请求可能传到一半断了要重来,体验断断续续。所以弱网最怕的是“大”和“多”——资源体积大、请求次数多,在弱网下都会被成倍放大成漫长的等待。
再说低端机。低端机的瓶颈在于算力和内存。CPU性能弱,最直接的后果是解析和执行JavaScript慢得多——同一段脚本,高端机几十毫秒跑完,低端机可能要几百毫秒甚至更久,这期间页面是卡住的、点了没反应的。内存小,则意味着同时能处理的东西有限,页面太重、脚本太多,容易卡顿甚至崩溃。屏幕和浏览器也可能偏旧,对新特性支持不好。所以低端机最怕的是“重”——JavaScript重、页面结构重、运行时负担重,这些都会卡在它孱弱的CPU上。
把这两个瓶颈翻译成大家熟悉的性能指标,就更清楚了。弱网主要拖垮加载类指标,比如LCP(最大内容绘制,首屏主要内容多久能显示)——资源下载慢,首屏自然出得慢。
低端机主要拖垮交互类指标,比如INP(交互到下一次绘制,点击后多久有反应)——CPU忙着解析执行脚本,没空响应你的点击,按钮就像没按下去一样。web.dev — Optimize Largest Contentful Paint(官方拆解LCP由资源加载延迟、渲染阻塞等环节构成及优化方法) (https://web.dev/articles/optimize-lcp)里把LCP拆成了资源加载延迟、渲染阻塞等几段,弱网恰恰是在资源加载这段疯狂拖后腿。
理解了这个,后面的优化思路就有了主线:对付弱网,核心是给资源减重、给请求减量;对付低端机,核心是给JavaScript和运行时减负。两条主线交织,就是接下来几节要拆的具体打法。先从收益最大的那一刀——图片,开始。
## 图片是弱网下最大的累赘,怎么给它瘦身?
如果弱网优化只能做一件事,保哥会毫不犹豫地说:先搞定图片。原因很简单,在绝大多数电商和独立站页面上,图片是体积占比最大的资源,往往占到整个页面下载量的一大半甚至更多。对带宽紧张的弱网用户来说,图片就是压在他们网速上最重的那块石头。把图片瘦身做好,是投入产出比最高的一刀,没有之一。给图片瘦身,有几个层层递进的手段。
第一,换用现代图片格式。很多站还在用老旧的JPEG、PNG,体积偏大。换成WebP这样的现代格式,能在几乎看不出画质差别的前提下,把文件砍小一大截。web.dev — Use WebP images(WebP通常比同质量JPEG/PNG小25–35% 的官方说明) (https://web.dev/articles/serve-images-webp)里给的数据是,WebP通常比同质量的JPEG、PNG小百分之二三十,更新的AVIF格式还能更小。光是把全站图片转成WebP,弱网用户的图片下载量就能直降一截,这一步性价比极高。
第二,按设备尺寸提供合适大小的图,别让手机下载电脑用的大图。一个常见的浪费是:不管用户屏幕多大,一律推送同一张为大屏准备的高清大图。手机屏幕就那么大,塞给它一张几千像素宽的图,绝大部分像素是浪费的,弱网用户却要为这些用不上的数据买单。用响应式图片的手段(比如srcset配多个尺寸),让浏览器根据设备屏幕自动挑选合适大小的版本,手机就拿手机该用的小图,能省下大量带宽。
第三,老老实实做压缩。很多图片直接从设计稿或相机里导出来就上传了,没经过压缩,藏着大量可以挤掉的水分。用图片压缩工具或自动化的处理流程,在可接受的画质范围内把每张图压到最小,是个一劳永逸的好习惯。关于图片的格式、压缩、命名这些细节,保哥在网站图片SEO优化技巧 (https://zhangwenbao.com/website-photo-seo-optimization-techniques.html)那篇里讲得很细,这里不展开,但弱网场景下,图片压缩的优先级要再往前提。
第四,懒加载首屏以外的图片。一个页面往往有很多图,但用户一打开只看得到首屏那几张,下面的要滚动才看得到。没必要在一开始就把所有图都下载下来——用懒加载,让首屏外的图片等用户快滚动到时再加载。web.dev — Browser-level image lazy loading(用原生loading属性延迟加载首屏外图片、省带宽的官方指南) (https://web.dev/articles/browser-level-image-lazy-loading)说明了用原生的loading属性就能轻松实现这一点,省下的初始带宽对弱网用户意义重大。
但这里有个关键的坑——首屏内的图片绝对不能懒加载,尤其是首屏那张最大的主图,懒加载它会直接拖慢LCP,这点保哥在FAQ里专门讲。
这四步做下来,图片这块的体积通常能压掉一大半。对弱网用户,这意味着页面从转好几秒才出图,变成图片唰地就刷出来了,体验是质变的。所以再强调一遍:弱网优化,从图片开刀,收益最快最猛。
## JavaScript在低端机上为什么是性能杀手,怎么减负?
如果说图片是弱网的头号敌人,那JavaScript就是低端机的头号杀手。这两个要分开理解:图片再大,浏览器下载下来显示就行,不怎么费CPU;而JavaScript不光要下载,下载完还得让CPU去解析、编译、执行,这个解析执行的过程,在CPU孱弱的低端机上会慢得令人发指。
具体会发生什么?当大量JavaScript涌进来,低端机的CPU被占满,主线程被一个个长任务堵死。这期间,页面对用户的任何操作都没法响应——你点了按钮,它在忙着跑脚本,没空理你,要等好几百毫秒甚至更久才反应过来。在用户感受上,这就是“这网站怎么点了没用、卡死了”。前面说的INP指标差,根子大多在这。这个主线程被长任务堵塞的机制,正是INP(交互到下一次绘制)恶化的根源,低端机只是把这个问题放大了无数倍。
怎么给JavaScript减负?核心思路是四个字:少、晚、散。
“少”,就是减少JavaScript的总量。最大的水分往往来自第三方脚本——各种分析、客服、弹窗、营销插件,每一个都往页面里塞自己的一坨JS。前面讲应用栈治理时说过,这些第三方脚本是性能的重灾区,能砍的坚决砍,留下的也要审视它值不值这个性能代价。自己写的代码,也尽量精简、别引入用不上的大型库。总量降下来,低端机的CPU负担直接减轻。
“晚”,就是延迟加载非关键的JavaScript。不是所有脚本都得在页面一打开就执行。和首屏渲染、核心交互无关的脚本——比如底部的统计、不在首屏的功能模块——可以用延迟加载的方式,等关键内容渲染完、甚至等用户有交互意图时再加载执行,别在最金贵的首屏阶段跟核心内容抢CPU。
“散”,就是别让单个任务把主线程占太久。把又大又长的JavaScript任务拆成小块,给浏览器留出响应用户操作的空隙,避免一个长任务把主线程一占就是大半秒,用户点啥都没反应。这一步偏技术,但对改善低端机上的卡顿感效果很直接。把“少、晚、散”这三招用上,你的页面在低端机上的“跟手”程度,会明显不一样。
## 怎么让首屏在弱网下尽快出来,先抓住用户?
弱网用户的耐心是以秒计的,转圈超过几秒,很多人就走了。所以有一个策略性的取舍极其重要:与其让用户对着白屏等整个页面都加载完,不如想尽办法让首屏——用户一打开看到的那一屏——尽可能快地先出来,先抓住他,剩下的边滚边加载。这就是优化关键渲染路径的思路。
要让首屏尽快出来,得先搞清楚什么在挡着它。浏览器要渲染出首屏,需要拿到关键的HTML、CSS,有时还要等字体。这其中任何一个是“渲染阻塞”的、或者下载很慢,首屏就被卡住。优化的方向,就是把首屏真正需要的东西最快送到,把不影响首屏的东西往后推。
第一招,优先保障首屏内容和它的关键样式。把渲染首屏所必需的那部分关键CSS尽早就位(比如内联进HTML),让浏览器拿到HTML就能立刻把首屏画出来,而不用干等一个完整的大样式表下载完。首屏用不到的样式,可以延后加载。哪些算首屏关键内容、怎么排布局,保哥在首屏内容与页面布局机制 (https://zhangwenbao.com/above-the-fold-content-seo-page-layout-mechanism.html)那篇里有专门的拆解,弱网下,“把价值塞进首屏、让首屏最快出来”这件事的权重要再调高。
第二招,管好字体,别让它拖白屏。如果用了自定义网络字体,弱网下字体文件下载慢,可能导致文字迟迟不显示(白屏等字体)。解决办法是设置合理的字体显示策略(比如让文字先用系统备用字体显示出来,自定义字体到了再替换),别让用户对着没有文字的页面干等。涉及中文字体的还要格外当心体积问题,这点FAQ里细说。
第三招,用骨架屏之类的手段管理等待感知。弱网下加载需要时间是客观现实,但你可以让这个等待不那么难熬。与其显示一片空白或者一个干转的圈,不如先渲染出页面的骨架结构(灰色的占位块,勾勒出内容大概的样子),让用户感觉“它在加载、马上就好”,而不是“它是不是卡死了”。这虽然没真的让加载变快,但显著改善了用户对速度的主观感受,降低了弱网下的跳出。
这三招合起来是一个心法:在弱网下,先让用户看到东西、看到希望,比让他看到完整的页面更重要。首屏抢跑成功,你就争取到了让他继续等下去、继续逛下去的机会;首屏迟迟不出,再好的内容他也看不到了。
## 弱网的“不稳定”怎么应对,别让用户卡在半路?
前面讲的多是“慢”,但弱网还有一个更难缠的特性——“不稳定”。它不是匀速地慢,而是时快时慢、时断时续,信号好的时候还行,一进电梯、一过隧道、一到信号死角,连接就抖动甚至中断。针对这种不稳定,光做“快”不够,还得做“稳”和“容错”,别让用户在网络抖一下时就卡死在半路、前功尽弃。
第一,把能缓存的尽量缓存下来,减少对网络的依赖。用户第一次访问加载过的资源——比如logo、图标、CSS、JS、字体这些不常变的静态文件——通过合理的缓存策略存在他本地,下次再访问、或者在站内跳转时,就能直接从本地拿,不用再走一遍弱网。这样即便网络抖动,已经缓存的部分照样能用,体验稳得多。更进一步,可以用Service Worker做更主动的缓存控制,甚至让一部分内容在断网时也能展示。
第二,对可能失败的网络请求做容错和重试。弱网下请求失败是常态,不是异常。如果你的页面在一个请求失败后就彻底卡住、白屏、或者报个用户看不懂的错,那体验就崩了。更稳妥的做法是:关键请求失败了,自动悄悄重试一两次;万一确实拿不到,给一个友好的提示和重试按钮,而不是让用户对着卡死的页面发懵。让页面在网络出问题时“优雅地降级”,而不是“粗暴地崩溃”。
第三,避免把太多东西压在一个大请求上。如果你的页面要靠一个巨大的请求一次性把所有数据都拉回来才能显示,那在弱网下,这个大请求一旦慢了或者断了,整个页面就全完了。把数据请求拆细、让页面能分块渐进地展示——核心内容先到先显示,次要内容后到后补上——既能让首屏更快,也能让单个请求失败时的影响面更小,不至于一损俱损。
这一节的思路,和前面追求“快”是互补的:快,是让顺利的时候更顺;稳和容错,是让不顺利的时候不至于全盘崩掉。弱网用户的网络注定会时不时掉链子,你的页面能不能在掉链子时还撑得住、还给用户留条退路,往往就是“勉强能用”和“彻底用不了”的分界线。说到底,给弱网用户做体验,要默认网络是会出问题的,然后为出问题那一刻做好准备。
## 怎么测出真实海外低端机弱网的体验,而不是自欺欺人?
讲了这么多优化手段,最后必须回到最开始那个盲区——测试。如果你还是只拿旗舰机连快网测,那做再多优化你也不知道效果,甚至不知道还有哪些问题没解决。要让优化真正落地,你得先有办法测出接近真实低端机弱网用户的体验。好在这件事门槛并不高,几种办法搭配着用就够了。
第一,用浏览器开发者工具的双节流。这是最方便、最该养成习惯的一招。Chrome开发者工具里有网络节流和CPU节流:网络节流把你的快网限速成模拟的4G、3G,重现弱网;CPU节流把你的高性能电脑降速成模拟低端设备,重现CPU慢。两个一起开到位,再走一遍你的页面,平时被高配掩盖的卡顿立刻原形毕露。这套不花一分钱,却能解决大部分盲测问题。
第二,用Lighthouse跑移动端审计。Lighthouse(Chrome自带、PageSpeed Insights也在用)跑移动端测试时,默认就是在模拟的移动设备加节流网络下进行的,所以它给的移动端分数本就比你肉眼感受严苛。把它当成一个能纵向对比的体检工具:优化前后各跑一次,看LCP、INP这些指标有没有改善,比凭感觉靠谱得多。它还会直接列出具体的优化建议,照着排查很省事。
第三,条件允许就上真机和现场数据。模拟终究是模拟,和真实的低端安卓机、真实的当地网络还是有差距。条件允许的话,弄一两台目标市场常见型号的真机实测,或者用云端的远程真机测试服务,在接近真实的环境下走一遍关键流程,能逮到模拟器漏掉的问题。更进一步,通过真实用户监控(RUM)和Search Console的核心网页指标报告,看你真实用户在现场的实际指标分布——这是最真实的数据,因为它直接来自你客户的真机真网,不掺一点想象。
这几招的关系是层层逼近真实:开发者工具双节流用于日常快速自查,Lighthouse用于优化前后的量化对比,真机和现场数据用于最终验证真实体验。核心就一条铁律——别再拿你的旗舰机当标准了。你的客户不在你的测试环境里,你得主动把测试环境,调到你客户真实所处的那个又弱又慢的世界里去,优化才有意义。
## 海外弱网移动端优化最容易踩的5个坑是什么?
最后照例上一份保哥的踩坑清单。这五个坑,是为弱网做优化时最常见的几种栽法,对照着自查,能帮你少走弯路。
坑一:只用高端机快网测,根本没意识到问题存在。这是所有坑的根源,也是最普遍的。你的测试环境太好,把所有性能问题都掩盖了,于是你压根不知道海外低端机弱网用户在经历什么。破解它的唯一办法,就是逼自己用节流工具、用真机,去真实地感受一次客户的卡顿。意识不到问题,谈何解决。
坑二:把首屏图片也加了懒加载,弄巧成拙。懒加载是好东西,但用错地方会坏事。给首屏内、尤其首屏那张主图加懒加载,会让浏览器一开始不去加载它、要显示时才临时拿,直接拖慢LCP。记住懒加载只给首屏以外、需要滚动才看到的图片用,首屏图片要正常甚至优先加载。这是个高频低级错误,对照检查一下你的页面。
坑三:图片不优化,光指望上CDN解决一切。CDN能让资源传得更近更快,但它没法替你把一张几MB的巨图变小,再近的CDN也得把这几MB实实在在塞过弱网。顺序应该是先给图片和资源彻底瘦身、把体积砍下来,再上CDN加速,别本末倒置地指望CDN替你擦屁股。先减重,再加速。
坑四:为了轻量把内容和功能也砍了,矫枉过正。做轻是对的,做残就错了。把页面做精简、砍掉花哨无用的特效是对的,但用户要看的产品图、要读的关键信息、要走的购买流程一样都不能少。轻量化的目标是让真实内容在弱设备上流畅可用,不是用阉割体验去换一个好看的速度分数,砍出一个加载飞快但转化崩盘的页面,是赔本买卖。
坑五:忽略中文等大字体文件这个隐形炸弹。做面向海外的站,如果页面涉及中文等CJK内容又用了自定义字体,要格外当心——一个完整中文字体动辄几MB,砸到弱网上是灾难,却很容易被忽略,因为在你的快网上它一闪就下来了。要么用系统字体,要么做字体子集化只保留用到的字。别让一个被你忽略的字体文件,成了弱网用户打开网站时最大的那块绊脚石。
把这五个坑都避开,再加上前面那套优化,你的独立站在海外低端机弱网下的表现,会和现在判若两站。配套地,先用出海DTC极简设计的8步转化法 (https://zhangwenbao.com/overseas-dtc-kiss-minimalist-design-8step-conversion.html)那篇的思路把设计做克制,弱网优化会事半功倍——因为最快的资源,永远是你根本没加载的那个。
## 常见问题解答
## 我没有那些低端安卓机,怎么测真实的弱网卡顿体验?
不用真去买一堆千元机,浏览器开发者工具就能模拟个八九不离十。Chrome开发者工具里有网络节流和CPU节流两个开关:网络节流把你的快网限速成模拟的4G、3G,重现弱网下载慢、延迟高;CPU节流把高性能电脑降速成模拟低端设备(比如4到6倍降速),重现低端机解析执行JavaScript慢的窘境。两个一起开到位再跑一遍页面,平时被高配掩盖的卡顿立刻现形。Lighthouse跑分默认用的也正是模拟移动设备加节流的环境,所以它的移动端分数本就比你肉眼感受的严苛。当然模拟终究是模拟,条件允许就弄一两台目标市场常见型号的真机、或用云端远程真机服务走一遍关键流程,能发现模拟器漏掉的问题。但对多数中小站长,先把双节流用起来,就能解决八成的盲测问题。
## 图片优化和上CDN,哪个对弱网体验提升更大?应该先做哪个?
两个都重要,但只能先做一个的话,建议先啃图片,投入产出比更高也更可控。CDN解决的是内容离用户更近、传输更快,但你的图片要是几MB的巨无霸,再近的CDN也得把这几MB实实在在塞过弱网管道,用户照样等。而图片优化是从源头砍数据量——把一张2MB的图压成200KB,弱网下载时间直接缩到十分之一,这是任何CDN都替代不了的。理想情况是两个一起做:先用WebP、响应式尺寸、压缩、懒加载把图片彻底瘦身,再上一个在目标客户地区节点充足的CDN就近送达。但资源精力有限时,先做图片瘦身,往往能用最小成本拿到最明显的弱网体验提升。先减重,再加速,顺序别搞反。
## 为弱网做了一堆优化,会不会反而把高端机用户的体验做差了?
基本不会,恰恰相反,绝大多数弱网优化对高端机用户也是净收益。你想,图片更小、JavaScript更少、首屏更快——这些改进在高端机快网上同样成立,只不过高端用户本来就快,提升的绝对值没那么戏剧化,但页面变轻、变快对他们一样是好事,没有谁会因为页面加载更快而不高兴。真正需要留意的是少数“自适应”手段别做过头:比如根据网络状况给弱网用户发低清图、给快网用户发高清图,这种分级如果实现得糙,可能让高端用户看到的画质打折。但这属于精细化的取舍,做的时候把握好分寸、给好网络足够好的版本就行,不是不做弱网优化的理由。保哥的态度很明确:性能优化的大方向上,弱网和高端机的利益是一致的,让最弱的设备能用,强设备只会更爽,不存在“为了照顾穷设备牺牲富设备”这种伪矛盾。
## 新兴市场用户网络这么差,是不是干脆做个超级精简的版本就行了?
做轻是对的,但别走到“做残”那个极端。把页面做精简、做轻量,砍掉花哨无用的特效、删掉用不上的第三方脚本、让设计回归克制,这个方向完全正确,弱网用户会感激你。但精简不等于把内容和功能阉割掉——用户要看的产品图、要读的关键信息、要走的购买流程,一个都不能少,少了就不是快不快的问题,是能不能成交的问题了。正确的做法是“该有的都有,但每一样都做到最轻”:图片该展示还展示,只是用最优格式压到最小;功能该提供还提供,只是把实现做到最省资源;首屏该传达的价值一点不缺,只是用最快的方式先送达。保哥见过有人矫枉过正,为了极致轻量把产品详情砍得七零八落,结果加载是快了,转化反而崩了,得不偿失。轻量化的目标是让真实的内容和功能在弱设备上流畅可用,不是用牺牲体验去换一个好看的速度分数。
## 懒加载是不是把所有图片都加上loading=lazy就万事大吉了?
方向对,但有个关键细节很多人做反了——首屏内的图片千万别懒加载。懒加载的原理是延迟加载那些首屏外、用户暂时看不到的图片,等用户滚动到附近再加载,这样能省下初始加载的带宽,对弱网帮助很大。但如果你无脑地给页面上所有图片都加上lazy,包括首屏最顶部那张最大的主图,反而会坏事:浏览器一开始不去加载它,等到要显示时才临时去拿,首屏最重要的那个元素就被推迟了,LCP(最大内容绘制)不升反降。正确的做法是分清楚——首屏内、用户一打开就看到的关键图片,让它正常优先加载,甚至可以用预加载提示让它更快;首屏以下、需要滚动才看到的图片,才加lazy延迟加载。简单说,懒加载是给“看不见的”图片用的,给“一眼就看到的”图片用,等于自己拖自己后腿。这个边界划对了,懒加载才是弱网下的利器。
## 字体加载会拖慢弱网体验吗?中文站要注意什么?
会,字体在弱网下是个容易被忽略的拖累,尤其涉及非系统字体时。原理是:用了自定义网络字体,浏览器要先下载字体文件才能渲染文字,弱网下这个下载很慢,期间可能出现两种尴尬——文字先不显示、等字体到了才出现(白屏一段,叫FOIT),或先用系统字体顶上、字体到了再替换(闪一下,叫FOUT)。处理办法是设置合理的font-display策略(一般用swap,让文字先用备用字体显示,别让用户对着空白等),并尽量精简、只加载真正用到的字重。但涉及中文等CJK内容要格外当心:中文字体动辄几MB,一个完整字体包砸到弱网上是灾难,要么用系统字体,要么做字体子集化——只把页面用到的字打成一个很小的子集。别让一个字体文件,成了弱网用户打开网站时最大的那块石头。
## 权威参考资料