背景:在测试一个从0到1的小程序项目时经常出现崩溃、卡死的现象,开发和测试排查艰难耗时良久,由此萌生了梳理小程序性能影响因素和测试设计关注点的想法。
总结在前面:
一、影响页面性能的因素
- 页面性能:从用户体验角度看小程序性能即“响应时间和是否崩溃或卡死(内存)”。
- 体现性能情况的功能场景:根据页面的生命周期可以拆分为以下三个场景“页面加载与渲染”、“页面交互”、“动效流畅度”。
- 影响响应时间的因素:响应往往涉及前后台数据交互,数据交互的速率受到包括“网络速度快慢”、“请求内容大小”、“服务响应速率快慢”、“数据处理速度(指前端数据解析等一系列操作)”等因素的影响。
- 影响内存的因素:基本可以分为两个场景“短时间内占用了过多的内存”、“内存的长久持有不释放”。
- 小程序页面生命周期和实际使用场景如下图所示:
由一.5,我们可以将页面性能分为页面加载和页面数据更新两个场景进行分析
二、页面加载
1.页面加载涉及哪些资源
代码包资源:开发者打包在小程序代码包里的资源
a.代码文件:HTML、CSS、JavaScript
HTML文件:页面结构和内容,包括页面的标签、组件、文本等
CSS文件:控制页面样式,包括页面的布局、颜色、字体等样式
JavaScript文件:逻辑控制,包括页面交互、事件响应、数据请求等功能处理
b.图片资源:页面使用的背景图和icon图标等
c.音视频资源:页面使用的音频和视频资源
d.字体资源:页面使用的字体文件
外部资源:通过数据请求等方式即使获取的实时数据或配置类资源
e.外部资源:以上bcd资源以CDN形式进行加载页面功能请求的数据资源(如文件列表)
2.页面加载的过程
参见微信官方提供的小程序启动流程: https://res.wx.qq.com/wxdoc/dist/assets/img/launch-1.0a7b0904.svg https://res.wx.qq.com/wxdoc/dist/assets/img/launch-1.0a7b0904.svg https://res.wx.qq.com/wxdoc/dist/assets/img/launch-1.0a7b0904.svg 简化流程如下:
3.加载过程中有哪些可能引发性能问题的关注点和对应测试点举例(该阶段可测性和测试点不多,作为冷启动步骤拆解了解)
资源下载阶段:该阶段性能卡点主要在下载耗时上,耗时主要影响因素除网络速度外
主要是代码包体积大小和外部资源大小。
对应测试关注点:
1.打开页面所下载的资源是否都为必要资源--分包策略和预加载策略
小程序存在几个相互解耦的功能或页面且这几个功能或页面的资源文件都
比较大的时候可以采用分包策略在资源必要时(使用对应功能和打开对应
页面时)分批下载对应代码包,同时可以使用预加载的方式在该功能或页
面的上一到两个层级提前静默下载代码包避免使用时出现等待,影响用户
体验。
举例:扫描小程序进入首页需要的资源为首页布局、内容信息、事件响应
等等代码文件和图标资源文件,对于下一步拍摄所需的相机控制和图片处
理模型等文件都不是必须的。那此时可采取分包策略,将首页和
拍摄及后续图片处理逻辑分为两个代码包,首次打开小程序的时候只需要
下载首页代码包即可,大大减少了代码包的下载时间。当然这种策略也会
带来一些问题,比如点击拍摄按钮的时候会先loading一段时间才能打开
对应页面,用户使用流程不流畅,存在阻断性体验问题。针对这种问题我
们可以采用预加载的办法,即首页的资源加载完成或页面渲染完成后就可
以后台静默下载拍摄代码包了,这样既可以错峰下载降低用户首页加载等
待时间又可以避免阻断性体验问题。
2.图片和音视频资源是否有可压缩空间:在保证清晰度的情况下是否可以通过
一些压缩技术来减少图片个音视频资源的大小,可采用对应的压缩工具(例如
TinyPng、FFmpeg、AUdacity等等)和调整尺寸、分辨率、码率、采样率、
编码方法、格式转换等进行压缩。在测试时可以找开发所要相关资源的大小信
息,判断这些资源是否过大,或使用上述方法进行压缩后查看资源展示效果是
否满足使用条件,在可使用的前提下压缩的尽可能的小。
3.不可压缩的较大资源是否可通过配置下发的形式来获取:2中资源若为了保
证使用体验而无法进一步压缩且资源较大的情况下,可以通过外部链接CDN下
载的形式来获取,在代码包里只需写入资源对应url和下载时机即可。此时测试
需要关注该类资源的下载时机是否合理,是否能保证在渲染时可以下载解析完
成,以及下载的资源的成功率和失败时的兜底措施是否合理。
总结上述2、3即为:关注开发写入代码包资源大小和可压缩空间、关注是否可采用
外链资源下载方式及下载的时机合理性、关注外链资源下载失败兜底方案。
解析编译阶段:如上冷启动流程图所示,解析编译阶段主要做两件事“代码文件解析编
译”、“注册页面&页面路由”。上面一.5已经解释了三种代码文件的作用就不再赘述,这里
解释一下注册页面&页面路由的含义:参考文档页面配置 | 微信开放文档
注册页面:告诉小程序有哪些页面存在,配置在app.json文件中,信息包括:页面
路径、页面标题、页面框架样式等。
页面路由:告诉小程序页面之间的跳转管理和方式,是卸载js文件里的。
顺便说一下页面跳转方式:详见页面路由 | 微信开放文档
代码文件编译解析性能影响因素:页面结构的复杂度,越复杂则解析和布局的时间越
长。所以如果一个页面存在多层嵌套和很多元素,测试的时候需要更加关注页面冷启
动时的耗时情况 。
页面注册和路由性能影响因素:页面的数量越多、页面标题和样式等内容的越复杂占
用的内存就越多,耗时越长。
故解析编译阶段页面数量越多,页面结构越复杂,耗时越长,内存占用越高,越需要
关注启动时长和内存占用情况。
页面渲染阶段:获取上面几步处理的数据在视图层进行渲染展示。
详情可见初始渲染缓存 | 微信开放文档。这里除了上述的精简页面复杂程度来提高性能
外,还可以采用页面数据缓存的方式提高下次打开页面的性能。页面信息缓存到本地缓
存中,下次打开页面直接从本地缓存中取数据并进行展示,大大缩短用户的等待时间。
可缓存的页面信息包括:页面骨架、静态资源、自定义提示、广告位等等。进行页面缓
存的同时需要关注本地缓存上限为10MB超过限制会存储失败。小程序缓存机制可见下图
进行粗略了解:
三、数据更新频率
1.为什么会对性能造成影响?
- 频繁更新数据会导致页面频繁重绘,会导致渲染线程忙碌,出现页面卡顿、延迟等情况。
- 消耗CPU和内存资源,频繁更新会导致系统资源处于高负载状态,性能不支撑时会出现卡顿甚至崩溃的情况
- 网络请求增多,消耗网络带宽等资源,增加服务器负担和网络延迟,影响响应时间和页面加载速度
- 耗电量增加,持续的数据处理导致耗电量快速上升
2.数据更新核心方法:
setData方法,用户将数据从逻辑层传递到视图层并更新页面的核心方法(仅做科普,若有开发提及可知是用来做什么的。)
3.数据更新频繁的场景与实例:
注:数据量大的场景的调用频率和渲染流畅度需要重点关注
a.实时更新数据:自动实时更新展示数据的场景,如:直播间的画面、评论、礼物等;导航地
图的路线、方向等;外卖订单的状态;上传下载模块加载等的进度;前后端长链接持续推送
消息,如语音速记功能。
b.交互时事件响应频次高:手动操作过程中会多次触发页面渲染的场景,如:列表的滑动动作;
按钮的连续点击动作;模块拖动移动动作;窗口大小拖动调整动作;
以扫描小程序文件列表举例:
问题表现:若每次滑动都会重新渲染整个列表内容的话,会发现越往下滑越卡顿。
问题原因:
每次滑动都会触发页面渲染,持续滑动就会持续触发渲染。
随着下滑,每次渲染的数据量都会变大,渲染耗时和资源占用增多。
解决方案:
每次只渲染当前页,不会对列表所有内容都进行渲染,只对需要展示的内容进行渲 染。
使用节流或防抖的方法限制渲染频次(节流和防抖的解释见下)。
缓存已渲染内容,避免重复渲染。
以扫描小程序提取文字划选功能举例:
问题表现:在图片区域划线选择文本框时会出现越划越卡顿的现象。
解决方案:使用防抖机制,限制渲染频次(防抖解释见下)。
问题原因:持续划线持续触发页面渲染。
以扫描小程序划选逻辑举例:该场景为数据量小的场景举例
该场景不会明显感知到卡顿,从性能曲线应能看到些微上涨,因为不断调整四个坐标点
的过程也会触发页面渲染,只是因为四边形框的数据量很小,不会带来明显影响。此类
场景可降级或暂不处理。
c.定时刷新:设置定时器,定时更新内容的模块。如轮播图、运营位等等。
d.页面变化:页面有多种模式可进行切换,如:多tab切换、部分区域有放大缩小按钮。
以扫描小程序逐行校对开关场景举例:
问题现象:多次点击逐行校对按钮进行模式切换的时候,页面渲染会逐渐卡顿。
问题原因:模式切换时渲染的数据量很大,资源占用多,切换时耗时久。
解决方案:做缓存,进行模式切换时即为缓存页面显示和隐藏的动作,而非每次都
进行页面的重新渲染。
4.常见预防(限频)方法
a.节流与防抖:
节流:在一定时间间隔只执行一次函数
防抖:在一定时间内只执行一次函数
区别:举例说明,现有一个确认按钮,在1s内连续点击了5次,每200ms一次。假设节流和防抖设置的时间间隔都是500ms,那响应请求的时间节流是第200ms、600ms,即设置时间区间的第一次请求会被响应,该时间区间后面的请求都被忽略,直至下一个时间区间接收到的第一个请求会再被响应,以此循环。防抖是第1.5s才响应,即设置的时间间隔为一个延时响应的时间,请求发起后开始倒计时,若倒计时期间无新的请求过来则发起该次请求,若中间有请求过来则重新倒计时继续等待响应。
b.批量更新数据:当需要更新多个数据时,合并为一个setdata进行更新而不要分别调用setdata。会持续触发setdata的动作,将时机调整为动作结束或其他比较合适的时机来批量处理连续动作的刷新渲染结果。
c.局部更新:只对需要刷新的部分进行更新而不进行全局更新,比如列表数据出现变化,只更新列表当前页甚至只更新列表对应行。
d.使用缓存:对频繁请求且变化数据量不大的数据进行缓存
e.只渲染可见部分:大量数据展示的场景,只渲染当前可见区域的数据,不渲染全部数据