用户从点开到看见内容,超过两秒就会开始怀疑网络。小程序的首屏时间和 H5 不一样,它受包体积、下载、注入、渲染四段影响,任何一段卡住,用户看到的都是白屏。
优化之前先量。不要凭感觉说“有点慢”,要拿到三个数:包体积、首屏请求数、首屏图片总字节。这三个数通常能直接指出问题在哪。
第一步:看主包是不是超了
微信小程序主包有 2MB 限制,很多项目把全部页面、组件、图片都塞进主包,首屏下载自然慢。把非首屏页面拆到分包,主包只留首页、登录、核心组件和公共样式。
拆包的原则是按业务路径拆,不要按文件类型拆。用户从首页到商品详情,这条路径上的页面放主包;个人中心、活动页、帮助中心放分包,用到时再下载。
拆完后看主包体积,能压到 1MB 以内最好。每减少 300KB,冷启动通常能快 100 到 200 毫秒,具体取决于网络。
第二步:图片是最大的变量
首屏 banner 用 200KB 的原图,是很多小程序的通病。按实际显示尺寸出图,宽度不超过屏幕宽度的 2 倍;用 WebP 或压缩后的 JPG;非首屏图片一律懒加载。
图标不要用图片。能用字体图标或 SVG 的就不要用 PNG,一张 20KB 的图标在首屏出现十次,就是 200KB。
还有一个容易忽略的点:图片要写死宽高,避免加载完成后页面跳动。首屏布局跳动会直接影响用户点击。
第三步:合并首屏请求
首页一进来就发五六个请求:配置、banner、推荐、公告、用户信息。每个请求 200 毫秒,串行就是 1 秒多。能合并的合并成一个“首页初始化”接口,不能合并的并行发。
接口返回只给首屏要用的字段。商品列表不要一次返回详情、规格、评价,首屏只需要图、名、价。其余字段等用户点进去再取。
缓存也要用起来。配置、分类这类不常变的数据,本地缓存 5 到 30 分钟,先渲染缓存再后台刷新,用户感知会快很多。
第四步:减少渲染阻塞
首屏不要做复杂计算,不要在小程序启动时同步读大量本地数据。setData 一次不要传大对象,分页数据分批 set。长列表用虚拟列表,不要一次性渲染几百条。
自定义导航栏和复杂动画也会拖慢首屏。如果必须用,先在骨架屏阶段完成布局,再加载内容。
验收:只在真机上算数
开发者工具的性能面板只能做参考。找一台三年前的中端安卓机,清缓存,连 4G,冷启动三次取平均。记录:白屏时长、首屏可交互时间、首屏图片完成时间。
再用微信开发者工具的“体验评分”跑一次,重点看启动性能和网络请求。两项都达标,再谈细节优化。
启动阶段的三个坑
第一,在 app.js 里同步读大量缓存,启动直接卡住。缓存读取放到页面 onLoad,异步处理。第二,首页同时发起登录、配置、定位三个请求,任何一个慢都拖住首屏。登录可以延后,配置走缓存。第三,自定义组件层级太深,渲染时间翻倍。首屏组件控制在三层以内。
还有一个常见问题:开发者工具里很快,真机上很慢。因为工具走的是电脑网络和 SSD,真机是 4G 加中低端 CPU。所有结论以真机为准。
上线后怎么持续监控
小程序后台的“性能分析”能看到启动耗时、页面切换耗时和错误率。每周看一次趋势,发现某次发版后首屏变慢,及时回滚。也可以自己在关键节点打点,记录从启动到首屏可交互的时间,按机型和网络分组。
首屏优化不是一次性的。每次加新功能,都重新量一次包体积和请求数,否则三个月后又回到原点。
相关阅读:响应式图片方案。
常见问题
分包后跳转会不会变慢?
第一次进入分包会下载,之后有缓存。把用户最常走的路径放主包,分包延迟基本感知不到。
首屏用骨架屏有用吗?
有用,但骨架屏要轻,不能比真实内容还复杂。它的作用是降低等待焦虑,不是掩盖慢。
图片用 CDN 能快多少?
通常能快 20% 到 40%,但前提是图片本身已经压缩。原图放 CDN,效果有限。
小程序性能和官网性能的底层逻辑相通,可以对照官网打开速度优化一起做减法。