为什么要做性能优化
一切性能优化都是为了体验优化
1. 使用小程序时,是否会经常遇到如下问题?
- 打开是一直白屏
- 打开是loading态,转好几圈
- 我的页面点了怎么跳转这么慢?
- 我的列表怎么越滑越卡?
2. 我们优化的方向有哪些?
- 启动加载性能
- 渲染性能
3. 启动加载性能
1.首次加载
小程序启动时,微信会为小程序展示一个固定的启动界面,界面内包含小程序的图标、名称和加载提示图标。此时,微信会在背后完成几项工作:下载小程序代码包、加载小程序代码包、初始化小程序首页。下载到的小程序代码包不是小程序的源代码,而是编译、压缩、打包之后的代码包。
2.加载顺序
小程序加载的顺序是如何?
微信会在小程序启动前为小程序准备好通用的运行环境。这个运行环境包括几个供小程序使用的线程,并在其中完成小程序基础库的初始化,预先执行通用逻辑,尽可能做好小程序的启动准备。这样可以显著减少小程序的启动时间。
3.控制包大小
提升体验最直接的方法是控制小程序包的大小,这是最显而易见的
- 勾选开发者工具中“上传代码时,压缩代码”选项;
- 及时清理无用的代码和资源文件(包括无用的日志代码)
- 减少资源包中的图片等资源的数量和大小(理论上除了小icon,其他图片资源从网络下载),图片资源压缩率有限
从开发者的角度看,控制代码包大小有助于减少小程序的启动时间。对低于1MB的代码包,其下载时间可以控制在929ms(iOS)、1500ms(Android)内。
4. 采用分包加载机制
根据业务场景,将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载;
使用分包时需要注意代码和资源文件目录的划分。启动时需要访问的页面及其依赖的资源文件应放在主包中。
5.采用分包预加载技术
当用户点击到子包的目录时,还是有一个代码包下载的过程,这会感觉到明显的卡顿,所以子包也不建议拆的太大,当然我们可以采用子包预加载技术,并不需要等到用户点击到子包页面后在下载子包,而是可以根据后期数据,做子包预加载,将用户在当先页可能点击的子包页面先加载,当用户点击后直接跳转;
这种基于配置的子包预加载技术,是可以根据用户网络类型来判断的,当用户处于网络条件好时才预加载;是灵活可控的
6.采用独立分包技术
目前很多小程序主包+子包(2M+6M)的方式,但是在做很多运营活动时,我们会发现活动(红包)是在子包里,但是运营、产品投放的落地页链接是子包链接,这是的用户在直达落地时,必须先下载主包内容(一般比较大),在下载子包内容(相对主包,较小),这使得在用户停留时间比较短的小程序场景中,用户体验不是很好,而且浪费了很大部分流量;
可以采用独立分包技术,区别于子包,和主包之间是无关的,在功能比较独立的子包里,使用户只需下载分包资源;
7. 首屏加载的优化建议
7.1 提前请求
异步请求可以在页面onLoad就加载,不需要等页面ready后在异步请求数据;当然,如果能在前置页面点击跳转时预请求当前页的核心异步请求,效果会更好;
7.2 利用缓存
利用storage API, 对变动频率比较低的异步数据进行缓存,二次启动时,先利用缓存数据进行初始化渲染,然后后台进行异步数据的更新,这不仅优化了性能,在无网环境下,用户也能很顺畅的使用到关键服务;
7.3 避免白屏
可以在前置页面将一些有用的字段带到当前页,进行首次渲染(列表页的某些数据--> 详情页),没有数据的模块可以进行骨架屏的占位,使用户不会等待的很焦虑,甚至走了;
7.4 及时反馈
及时的对需要用户等待的交互操作进行反馈,避免用户以为小程序卡了,无响应;
8.渲染性能优化
8.1.小程序渲染原理
双线程下的界面渲染,小程序的逻辑层和渲染层是分开的两个线程。在渲染层,宿主环境会把WXML转化成对应的JS对象,在逻辑层发生数据变更的时候,我们需要通过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,再经过对比前后差异,把差异应用在原来的Dom树上,渲染出正确的UI界面。
8.2.避免使用不当setData
在数据传输时,逻辑层会执行一次JSON.stringify来去除掉setData数据中不可传输的部分,之后将数据发送给视图层。同时,逻辑层还会将setData所设置的数据字段与data合并,使开发者可以用this.data读取到变更后的数据。因此,为了提升数据更新的性能,开发者在执行setData调用时,最好遵循以下原则:
8.2.1 不要过于频繁调用setData,应考虑将多次setData合并成一次setData调用;
8.2.2 数据通信的性能与数据量正相关,因而如果有一些数据字段不在界面中展示且数据结构比较复杂或包含长字符串,则不应使用setData来设置这些数据;
8.2.3 与界面渲染无关的数据最好不要设置在data中,可以考虑设置在page对象的其他字段下。
优化方案
1.尽量减少不必要的https请求,可使用 getStorageSync() 及 setStorageSync() 方法将数据存储在本地。
2.避免将未绑定在 WXML 的变量传入 setData: setData操作会引起框架处理一些渲染界面相关的工作, 一个未绑定的变量意味着与界面渲染无关,传入setData会造成不必要的性能消耗。如数据需要在当前页面共享,可采用定义全局变量的方式(如使用this.)。
3.避免每次 setData 都传递大量新数据: 导致js编译过程变慢,例如在改变data中某个数组的某个数据项是,在setData是可采用只更改某个数据项。列表数据量过大时,也可采用分步渲染加载的方法。
4.不能频繁调用setData(甚至一个函数里面不能调用两个setData函数): 滑动时会感觉到卡顿,操作反馈延迟严重, 因为 JS 线程一直在编译执行渲染,不能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层。
5.避免使用:active伪类来实现点击态,建议使用小程序内置组件的 'hover-class' 属性来实现。
6.避免使用.获取对象的深层属性,容易造成微信告警,可使用对象解构默认赋值,增加代码严谨性,不然小程序助手会告警报错。
7.避免页面节点嵌套过深,增加页面渲染压力。
8.页面退出之前销毁定时器,可在onUnLoad生命周期钩子函数中执行。
9.运用wx-for时,为循环节点添加key属性,一般情况下不用index值作为key值。
10.去掉无用的日志,方法,变量,类以及注释代码。
11.短时间内发起太多的图片请求,考虑使用图片懒加载和雪碧图方式。
12.减少页面的http请求次数,对于返回数据相同的接口,建议考虑使用数据缓存方式在当前页面存储数据。