小程序性能优化实践

性能报告

小程序整体的性能看板,可以分析小程序大致的性能表现。

评估等级分为“优秀”,“良好”,“一般”,“较差”四个档位。

性能评估:小程序整体的评级,评级依据暂时不详

启动性能:评估打开率,启动耗时,首次渲染耗时,JS 注入耗时指标。经观察发现打开率在 97% 以上才能达到良好,低于 97% 则为一般

网络性能:评估网络响应时长和错误率。经观察响应时间在 300ms 以内为优秀。

运行性能:评估页面切换性能。经观察切换时间在 400ms 以上为一般。

性能报告只能用于了解小程序大致性能水平,要针对小程序短板做特定优化还需要对每一阶段的性能数据进一步分析。

启动性能

在分析的过程中发现一些和我之前理解的有点不一样的地方,特此说明。

关于小程序启动的定义,官方定义是:以「用户打开小程序」为起点,到小程序「首页渲染完成」为止。「首页渲染完成」的标志是首页页面的 Page.onReady 事件触发。根据小程序启动流程解释,onReady 触发的时机在 onLoadonShow 之后,在视图层完成第一次渲染(也就是初始 data,不包括 onLoad 中同步设置的 data)之后返回。

由于我们一般会在 onLoad 回调中进行异步数据获取,此时页面很可能是白屏状态就触发了 onReady,所以「首页渲染完成」并不能表示用户真正看到页面的时机。对于动态页面来说一般会用骨架屏来优化这一阶段的用户体验,但骨架屏仅仅只能提升白屏的体验,对于减少用户实际等待内容的时间并无多大帮助。

关于冷启动打开率

小程序的打开率指的是在 冷启动 的情况下点击小程序到首屏渲染完成的留存率。冷启动是指小程序首次打开或者被销毁后再次打开的场景。

由于小程序的特殊性,点击右上角关闭按钮并不是直接关闭小程序,而是进入到了后台,此时再次进入小程序会有几种情况:

  1. 点击小程序图标再次进入小程序,会直接打开上次的页面,状态保留
  2. 点击其他的小程序链接,进入另一个页面,相当于进行了一次页面跳转(redirectTo)
  3. 点击其他小程序链接,进入同一个页面(path 相同但参数不同),相当于重新加载当前页面,onLoad 会重新触发

以上几种情况都属于热启动,小程序在后台 30min 以上,或者存在内存不足的情况下,微信会销毁小程序,下次打开还是相当于冷启动。

另外,小程序在前后台切换都会触发 onShow,包括直接把微信切换到后台,所以要尽量避免在 onShow 中调接口获取数据,如果必须要做的话,需要做好各种场景的判断。

冷启动打开率还和场景有很大关系,单聊场景下打开率会比群聊场景高很多。

总结

小程序打开率是以首页页面的 Page.onReady 触发时机计算,如果页面是动态数据页面,不代表页面实际展示,需要业务方自己通过 onLoad 发起数据请求和请求返回数据两个节点埋点(wx.reportEvent)进行数据统计。

T1:小程序冷启动 ———> onReady(首屏加载成功)
T2: onLoad(发起请求) ———> 请求返回 ——–> 数据二次渲染

Q:业务方为什么不在 onReady 为起点计算 T2?

A:onLoad 的时间会比 onReady 靠前一两百 ms,为了能够更快进行数据加载,我们一般在 onLoad 回调中发起请求,如果请求在 onReady 触发前返回,就无法计算出请求的时间。

下载代码包优化(资源准备阶段)

注意,冷启动 ≠ 下载代码包

是否需要下载代码包对冷启动性能有非常大的影响,可能会占用一半以上的时间,所以需要尽可能拆分代码包,减少无用的代码或者组件依赖。

切换到分包的页面其加载性能会大幅下降,需要使用例如独立分包分包预下载等技术加快分包页面的加载。

分包异步化

有时候我们发现即使拆了分包主包的大小还是很大,其中有很大一部分原因是主包和分包共用了一些组件或者方法,这些方法都放在了主包当中,如果要做极致的分包拆分,可以采用分包异步化的方案,可以实现不同分包之间组件相互引用和 JS 代码引用,有点类似 webpack5 中模块联邦的设计思想。

JS 注入优化(加载渲染阶段)

影响冷启动的另一半耗时在框架启动和初次渲染上,但这一部分对于业务开发者来说能优化的空间并不多。官方提供的优化方案是通过按需注入和用时注入的方法提高首屏的加载速度。

按需注入和用时注入只是延后了组件注入执行的时间,可能反而会增加页面切换的耗时和用户体验,而且配置后可能会造成一些未知的错误(找不到依赖),对整体性能影响可能不是特别大。

优化这个阶段的耗时主要还是要靠开发者自身良好的代码习惯,例如 app.json 中不要定义不常用的组件,及时清理页面不需要的组件,以及减少程序启动时同步执行 getSystemInfo/getSystemInfoSyncgetStorageSync/setStorageSync 这类耗时的 api。

网络性能

网络性能这块值得优化的方向有:

  1. 使用 DNS 预解析域名,优化首个接口的请求速度,预期能达到 100ms-200ms 的优化空间,但会带来额外的维护成本
  2. 优化接口调用时机,根据业务场景决定采用同步还是异步方案,是否优先展示页面主体内容,这一块做得好的话可能会有非常大的体验提升,主要还是依赖业务同学的经验和对 JS 异步流程的理解。

注意:微信小程序同时只能允许 10 个并发请求(wx.request, 不区分域名),这点和 web 应用有较大差异。

运行性能

主要是衡量页面切换耗时情况,页面依赖的组件越多,逻辑越复杂,加载速度越慢。

影响页面切换速度的主要影响因素有:

  1. 是否需要加载分包
  2. 视图层初始化
    1. 注入主包的公共代码(独立分包除外)
    2. (若页面位于分包中)注入分包的公共代码
    3. 注入页面代码
  3. 逻辑层初始化
    1. 上一个页面 onHide/onUnload
    2. 按需注入(如有)
    3. 当前页面 onLoad/onShow

官方优化文档优化方案分析

  • 按需注入对页面启动性能有较大帮助,但会对页面切换性能造成影响,但官方还是建议所有开发者打开这个特性,因为整体时间会有所下降。
  • 可以在上个页面调用 wx.navigateTo 跳转时,通过eventChannel进行数据传输,利用页面切换和初始化的时间提前进行数据加载。
  • 在合适的时机进行页面的预加载,由于小程序默认配置为当前页面 onReady 触发后 200ms 后出发预加载,而对于动态页面,此时页面正在进行数据请求以及 setData,在安卓上,渲染层所有页面的 webview 共享同一个现成,就会导致当前页面加载变慢,建议这类页面手动控制下一个页面的预加载时机。

小程序性能优化实践
https://www.wobushi.top/2023/小程序性能优化实践/
作者
Pride Su
发布于
2023年4月26日
许可协议