作者:腾讯增值业务项目管理人员
背景
为了满足日益复杂的小程序活动需求,腾讯增值服务项目组开发了活动小程序,该小程序以游戏社交圈为载体,为游戏玩家提供发帖、评论、点赞、分享等基础社交功能。
为了支持这些功能,我们做了一系列的性能优化改进。活动小程序一共有5个标签页,分别提供关注的人信息、所有用户的精美分享、发布图文的入口、消息、个人页面,如下图所示。
发展过程中面临很多挑战和问题,其中性能问题最为棘手,主要体现在以下几个方面:
小程序首次访问速度慢
需要上传大量UGC图片,速度慢,用户体验差。
当页面列表较长时,滚动不流畅
大量图片和视频的展示,很容易导致
由于标签页数量较多,内置图片素材很多,请求的后端接口很多,且用户发布的图片较大,导致小程序首次访问速度较慢,体验很差。
为此,我们首先进行了加载优化。
加载优化
装载优化的主要思路如下:
解决方案分为四个步骤:资源压缩、请求合并、延迟加载、数据缓存。
第一步,压缩依赖库代码,将复用的模块代码封装成组件,压缩内置本地图片大小,移除其他不必要的页面和组件,避免将其包含在总包中。
第二步,小图经过打包,避免发送网络请求。大图经过腾讯云压缩后再下载。同时,在微信小程序支持之前,我们进行了接口请求的合并,提升请求加载性能。
第三步,先加载首屏,对于一些不重要的资源,或者不会在首屏出现的图片、画布等,会进行延迟加载,以保证首屏速度,对于一些性能较差的机型,画布延迟加载效果会更好。
第四步,缓存,减少加载。不管是全局配置,还是首屏列表信息,还是公共图片,都进行缓存,保证内容优先显示。
优化结果如下:
上传优化
优化加载之后,小程序的加载速度明显变快,我们突破了第一个难关。很快,我们注意到第三个标签——发布页成为了瓶颈,因为这个页面可以同时上传9张相册照片(可以排成九宫格),现在的手机,不管是安卓还是iOS,随便拍一张就可能几MB,清晰度高一点的可能十几二十MB甚至更多。在这个基础上乘以9,哪怕是在wifi上高速上传,图片上传过程也会相当缓慢。为了鼓励用户多发帖、多发图片,我们必须解决这个问题。
所以发图片之前需要把图片压缩一下,再压缩一下,主要思路如下:
用户原有的相册图片比较大,经过QQ、微信压缩客户端一轮压缩后,大小一般在1-2M之间,乘以9后,最坏情况是有18M的图片需要上传,18M还是太大了,为此引入,通过按比例缩小原图的宽高,进一步压缩图片大小,保证单张图片大小不超过600k,压缩完成后通过并发请求上传多张图片,完成发布流程。
当然,实际过程比这复杂得多,其中的一些难点如下:
经过兼容性测试,我们发现部分机型存在图片绘制背景出现黑屏的情况,可以通过增加一层白色底图来解决该问题。在小程序中,尤其是上,画布不能太大,数量也不能太多,为了避免小程序只保留一张,所以只能一张一张的压缩,而这里就需要维护一个压缩队列。在QQ小程序中我们也遇到过图片左右移动时,图片宽高信息互换,导致压缩失败的情况。后来在官方同事的帮助下,终于解决了该问题。
优化结果如下:
渲染优化
经过上传优化后,单张图片上传速度提升了 71%,图片越大、数量越多,叠加效果越明显。基于此,普通用户终于实现了发图的自由。用户在发图上的活跃度越高,小程序的活跃度就越高。也意味着第二个标签页——发现页的内容越来越多,列表滚动越来越慢。我们要注意一个问题,就是页面渲染出现了问题。除了滚动卡顿,页面渲染还存在其他几个问题:
页面加载缓慢
刷新页面时视图晃动
下拉加载时,页面内容更新缓慢
渲染优化的主要思路如下:
小程序页面跳转时会有动画效果,这个效果完成后会触发页面回调,可以充分利用页面切换时的空隙,提前发送页面请求,从而达到页面预加载的目的,页面切换耗时大致如下:
众所周知,小程序采用双线程模型,如下图:
这使得操作涉及到线程间的通信,并且频繁发生,就像堵车一样,会导致两种后果:
除了数据传输之外,还需要一个脚本过程,大量的数据会增加js线程的负担,各种我们可以控制的点击、滚动事件都会被阻塞在js线程上,得不到响应。我们来看看数据量和传输时间的关系,如下图:
可以看出,当数据量小于 4kb 时,数据通信速度较快,单次传输时间小于 15ms。因此应该去除不必要的数据,特别是在长列表中,与视觉无关的数据越积越多,越影响传输效率。因此,我们可以有几种最佳实践:
前面我们提到,长列表的数据量和 DOM 量本来就很大,对于渲染来说是个天然的痛点。因此滚动事件必须做节流,尽量避免频繁查询节点信息、只更新局部可见区域的数据、延迟更新不可见区域的 view 等。另外页面画布设置为 ,在 iOS 下也会导致页面滚动卡顿,需要改为 ;由于 小程序同层渲染支持比较晚,在 早期版本下页面滚动可能会造成视频错位或者卡顿。
小程序的本质还是基于 H5,所以 H5 的优化策略还是有效的。比如减少 DOM 节点数和层级,意味着需要渲染的 DOM 更少;事件绑定更多利用委托机制,减少事件响应;自定义组件减少数据向上传递的层级。诸如此类的策略,都可以加快小程序的渲染速度。
优化结果如下:
页面加载时间减少了29%至41%,在性能较差的设备上效果更为明显。
优化前FPS帧率波动较大,平均帧率为.000,最低帧率为5FPS。优化后FPS帧率比较稳定,平均帧率为.000,最低帧率为.000。
内存优化
经过渲染优化后, 小程序整体速度快了很多。我们注意到发现页面支持无限下拉加载,列表可能很长,随着用户图片数量增多,是否会导致小程序卡顿?经过测试,性能不佳的模式再一次没有让我们失望,很多时候都符合预期。因此,内存问题一度成为瓶颈。
如何优化内存呢?首先节省内存,然后及时释放内存。
为了节省内存,图片和懒加载是基本策略。在 上使用 webp 图片也能有效减少约 25% 的内存消耗。研究发现,页面上长长的图片列表,经过腾讯云压缩后,下载的图片大小大大减少,进一步降低了内存消耗。但不管怎么节省内存,只要列表在加载新的图片,内存就会增加。因此我们动态移除了屏幕外的图片,用空白节点来占位。这个优化策略在列表滚动时以节流的方式执行,最终保证了图片内存的及时释放。
优化结果如下:
经过优化之后,初始内存降低了56M,无限加载图片的时候内存基本没有变化,我们和同类产品做一个简单的对比,如下图:
可以看到,对于小程序,内存峰值仅比初始值高出68M,内存维持在350M左右。对于微博小程序,内存峰值比初始值高出180M,并且内存还在增长。
以上就是我们针对活动小程序性能问题的一些优化实践,欢迎大家在下方留言交流。