本文首发于公众号「IT自学课堂」。
1 启动优化
1.1 启动流程
小程序在整个启动流程中,一般需要完成几项工作:
- 准备运行环境
- 下载,注入并执行对应小程序代码包
- 渲染小程序首页
开发者可以在第2,3去优化小程序的启动性能。
1.2 代码包大小优化
小程序在首次打开时,会去下载并执行代码包,随着代码包大小的上升,耗时也会相应增加。开发者可以采取以下方案:
-
使用分包技术
- 优势:对开发者而言,能使小程序有更大的代码体积,承载更多的功能与服务;而对用户而言,可以更快地打开小程序,同时在不影响启动速度前提下使用更多功能。
- 建议开发者按照功能的划分,拆分成几个分包,当需要用到某个功能时,才加载这个功能对应的分包。
-
独立分包
- 优势:分包预下载是为了解决首次进入分包页面时的延迟问题而设计的。如果能够在用户进入分包页面之前就预先将分包下载完毕,那么进入分包页面的延迟就能够尽可能降低。
-
分包预加载
- 优势:小程序中的某些场景(如广告页、活动页、支付页等),通常功能不是很复杂且相对独立,对启动性能有很高的要求。使用独立分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。
- 建议开发者将部分对启动性能要求很高的页面放到特殊的独立分包中。
- 独立分包与分包预下载使用教程
1.4 首屏渲染优化
**提前首屏数据请求 **
大部分小程序在渲染首页时,需要依赖服务端的接口数据,小程序为开发者提供了提前发起数据请求的能力:
- 数据预拉取:能够在小程序冷启动的时候通过微信后台提前向第三方服务器拉取业务数据,当代码包加载完时可以更快地渲染页面,减少用户等待时间,从而提升小程序的打开速度。
- 周期更新:在用户未打开小程序的情况下,也能从服务器提前拉取数据,当用户打开小程序时可以更快地渲染页面,减少用户等待时间。
**缓存请求数据 **
小程序提供了wx.setStorageSync等异步读写本地缓存的能力,数据存储在本地,返回的会比网络请求快。如果开发者基于某些原因无法采用数据预拉取与周期性更新,我们推荐优先从缓存中获取数据来渲染视图,等待网络请求返回后进行更新。
**精简首屏数据 **
此外,我们推荐开发者延迟请求非关键渲染数据,缩短网络请求时延,与视图层渲染无关的数据尽量不要放在 data 中,加快首屏渲染完成时间。
避免阻塞渲染
在小程序启动流程中,会顺序执行app.onLaunch, app.onShow, page.onLoad, page.onShow, page.onReady,所以,尽量避免在这些生命周期中使用Sync结尾的同步API,如 wx.setStorageSync,wx.getSystemInfoSync 等。
2 渲染优化
2.1 渲染时间优化
渲染时间指的是首次渲染或因数据变化带来的页面结构变化的渲染花费的时间。
渲染界面的耗时过长会让用户觉得卡顿,体验较差,出现这一情况时,需要校验下是否同时渲染的区域太大(例如列表过长),或渲染依赖的计算是否过于复杂。
2.2 使用自定义组件
自定义组件的更新只在组件内部进行,不受页面其他不能分内容的影响;比如一些运营活动的定时模块可以单独抽出来,做成一个定时组件,定时组件的更新并不会影响页面上其他元素的更新;各个组件也将具有各自独立的逻辑空间。每个组件都分别拥有自己的独立的数据、setData调用。
3 逻辑层JS优化
3.1 脚本执行优化
脚本执行时间是指JS脚本在一次同步执行中消耗的时间,比如生命周期回调、事件处理函数的同步执行时间。
执行脚本的耗时过长会让用户觉得卡顿,体验较差,出现这一情况时,需要确认并优化脚本的逻辑。
解决方案:一个执行周期内脚本运行时间不超过 1 秒。
3.2 小心后台页面JS
小程序中可能有n个页面,所有的这些页面,虽然都拥有自己的webview(渲染层), 但是却共享同一个js运行环境。也就是说,当你跳到了另外一个页面(假设是B页面),本页面(假设是A页面)的定时器等js操作仍在进行,并且不会被销毁,并且会抢占B页面的资源。
解决方案:页面销毁时,先清除页面中的定时器;
3.2 正确使用事件
视图层将事件反馈给逻辑层时,需要一个通信过程,通信的方向是从视图层到逻辑层。因为这个通信过程是异步的,会产生一定的延迟,延迟时间同样与传输的数据量正相关,数据量小于64KB时在30ms内。
解决方案:
- 去掉不必要的事件绑定(WXML中的 bind 和 catch),从而减少通信的数据量和次数;
- 事件绑定时需要传输target和currentTarget的dataset,因而不要在节点的data前缀属性中放置过大的数据。
3.3 谨慎使用onPageScroll 和 scroll-view组件的scroll事件
scroll 事件,也是一次通讯,是webview层向js逻辑层的通讯。这次通讯也是开销较大,如果考虑到这个事件被频繁的调用,回调函数如果有复杂的setData的话,性能就会很差。
解决方案:
- 只在必要时监听onPageScroll事件
- 不在onPageScroll中做复杂、耗时的逻辑处理
- 避免频繁查询节点信息(selectQuery)
- 当需要在频繁触发的用户事件(如 scroll 、 Resize 事件)中调用 setData ,合理的利用 函数防抖(debounce) 和 函数节流(throttle) 可以减少 setData 执行次数。
4 setData优化
setData是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。
4.1 setData调用频率优化
setData接口的调用涉及逻辑层与渲染层间的线程通信,通信过于频繁可能导致处理队列阻塞,界面渲染不及时而导致卡顿,应避免无用的频繁调用。
解决方案:每秒调用setData的次数不超过 20 次。
4.2 setData数据大小优化
由于小程序运行逻辑线程与渲染线程之上,setData的调用会把数据从逻辑层传到渲染层,数据太大会增加通信时间。
解决方案:
- 控制要更新的数据大小
- 只更新 变化的数据
- 保证setData的数据在JSON.stringify后不超过 256KB
4.3 setData数据冗余优化
setData操作会引起框架处理一些渲染界面相关的工作,一个未绑定的变量意味着与界面渲染无关,传入setData会造成不必要的性能消耗。
解决方案:setData传入的所有数据都与页面渲染有关,对于与页面渲染无关的变量,可以挂在页面或者组件的this对象上。
5 WXML优化
5.1 控制页面wxml节点数
建议一个页面使用少于 1000 个 WXML 节点,节点树深度少于 30 层,子节点数不大于 60 个。一个太大的 WXML 节点树会增加内存的使用,样式重排时间也会更长,影响体验。
解决方案:页面WXML节点少于 1000 个,节点树深度少于 30 层,子节点数不大于 60 个。
5.2 正确使用wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
解决方案:
- 保证wx:key值的唯一性
- wx:key使用教程
6 图片优化
6.1 开启图片缓存
开启 HTTP 缓存控制后,下一次加载同样的图片,会直接从缓存读取,大大提升加载速度。
解决方案:所有图片均开启 HTTP 缓存
6.2 图片大小优化
图片太大会增加下载时间和内存的消耗,应根据显示区域大小合理控制图片大小。
解决方案:如果储存图片的cdn支持,可以对图片进行剪裁,使请求的图片宽高都不超过实际显示宽高的3倍。
6.3 图片安全域名
使用 HTTPS,可以让你的小程序更加安全,而 HTTP 是明文传输的,存在可能被篡改内容的风险;
解决方案:使用 getHttpsImgUrl 函数,获取图片安全域名。
function getHttpsImgUrl(url = '') {
if(!url) return url;
var httpsUrl = '';
var domain = url.split('://')[1];
httpsUrl = 'https://' + domain;
return httpsUrl;
}
module.exports = {
getHttpsImgUrl: getHttpsImgUrl
};
6.4 图片请求数
短时间内发起太多图片请求会触发浏览器并行加载的限制,可能导致图片加载慢,用户一直处理等待。
解决方案:应该合理控制数量,可考虑使用雪碧图技术或在屏幕外的图片使用懒加载,保证每秒发起的图片请求数不超过 20 个。
6.5 应让图片按原图宽高比例显示
图片若没有按原图宽高比例显示,可能导致图片歪曲,不美观,甚至导致用户识别困难。
解决方案:可根据情况设置 image 组件的 mode 属性,以保持原图宽高比。
7 网络请求优化
7.1 网络请求数
短时间内发起太多请求会触发小程序并行请求数量的限制,同时太多请求也可能导致加载慢等问题
解决方案:合理控制请求数量,甚至做请求的合并等,保证每秒通过wx.request发起的请求数不超过 10 个。
7.2 请求耗时
请求的耗时太长会让用户一直等待甚至离开。
解决方案:应当优化好服务器处理时间、减小回包大小,让请求快速响应,保证网络正常的情况下,所有网络请求都在 1 秒内返回结果。
7.3 网络请求缓存
发起网络请求总会让用户等待,可能造成不好的体验,应尽量避免多余的请求。
解决方案:对同样的请求进行缓存,3 分钟以内同一个url请求不出现两次回包大于 128KB 且一模一样的内容。
8 wxss优化
8.1 提高wxss 覆盖率
大量未使用的样式,会增加小程序包体积大小,从而在一定程度上影响加载速度。
解决方案:
- 按需引入公用 wxss 资源;
- 删除页面中无用的wxss代码;
8.2 滚动区域可开启惯性滚动以增强体验
惯性滚动会使滚动比较顺畅,在安卓下默认有惯性滚动,而在 iOS 下需要额外设置 -webkit-overflow-scrolling: touch
的样式。
9 UI交互优化
9.1 合理设置可点击元素的响应区域大小
我们应该合理地设置好可点击元素的响应区域大小,如果过小会导致用户很难点中,体验很差。
9.2 固定底部的可点击组件都在iPhone X安全区域内
底部的可交互组件如果渲染在iPhone X的安全区域外,容易误触Home Indicator 。
关注我,一周3篇干货文章与你分享。
网友评论