内容整理于微信公开课javascript
一切性能优化都是为了体验优化html
打开是一直白屏java
打开是loading态,转好几圈web
个人页面点了怎么跳转这么慢?小程序
个人列表怎么越滑越卡?微信小程序
启动加载性能缓存
渲染性能性能优化
你是否见太小程序首次加载时是这样的图?bash
这张图中的三种状态对应的都是什么呢?微信
小程序启动时,微信会为小程序展现一个固定的启动界面,界面内包含小程序的图标、名称和加载提示图标。此时,微信会在背后完成几项工做:下载小程序代码包
、加载小程序代码包
、初始化小程序首页
。下载到的小程序代码包不是小程序的源代码,而是编译、压缩、打包以后的代码包。
小程序加载的顺序是如何?
微信会在小程序启动前为小程序准备好通用的运行环境。这个运行环境包括几个供小程序使用的线程,并在其中完成小程序基础库的初始化,预先执行通用逻辑,尽量作好小程序的启动准备。这样能够显著减小小程序的启动时间。
资源准备
(代码包下载);第二张图是
业务代码的注入以及落地页首次渲染
;第三张图是
落地页数据请求时的loading态
(部分小程序存在)
提高体验最直接的方法是控制小程序包的大小,这是最显而易见的
勾选开发者工具中“上传代码时,压缩代码”选项;
及时清理无用的代码和资源文件(包括无用的日志代码)
减小资源包中的图片等资源的数量和大小(理论上除了小icon,其余图片资源从网络下载),图片资源压缩率有限
从开发者的角度看,控制代码包大小有助于减小小程序的启动时间。对低于1MB的代码包,其下载时间能够控制在929ms(iOS)、1500ms(Android)内。
根据业务场景,将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载;
在4的基础上,当用户点击到子包的目录时,仍是有一个代码包下载的过程,这会感受到明显的卡顿,因此子包也不建议拆的太大,固然咱们能够采用子包预加载技术,并不须要等到用户点击到子包页面后在下载子包,而是能够根据后期数据,作子包预加载,将用户在当先页可能点击的子包页面先加载,当用户点击后直接跳转;
目前不少小程序主包+子包
(2M+6M)的方式,可是在作不少运营活动时,咱们会发现活动(红包)是在子包里,可是运营、产品投放的落地页连接是子包连接,这是的用户在直达落地时,必须先下载主包内容(通常比较大),在下载子包内容(相对主包,较小),这使得在用户停留时间比较短的小程序场景中,用户体验不是很好,并且浪费了很大部分流量;
7.1 提早请求
异步请求能够在页面onLoad就加载,不须要等页面ready后在异步请求数据;固然,若是能在前置页面点击跳转时预请求当前页的核心异步请求,效果会更好;
7.2 利用缓存
利用storage API, 对变更频率比较低的异步数据进行缓存,二次启动时,先利用缓存数据进行初始化渲染,而后后台进行异步数据的更新,这不只优化了性能,在无网环境下,用户也能很顺畅的使用到关键服务;
7.3 避免白屏
能够在前置页面将一些有用的字段带到当前页,进行首次渲染(列表页的某些数据--> 详情页),没有数据的模块能够进行骨架屏的占位,使用户不会等待的很焦虑,甚至走了;
7.4 及时反馈
及时的对须要用户等待的交互操做进行反馈,避免用户觉得小程序卡了,无响应
双线程下的界面渲染,小程序的逻辑层和渲染层是分开的两个线程。在渲染层,宿主环境会把WXML转化成对应的JS对象,在逻辑层发生数据变动的时候,咱们须要经过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,再通过对比先后差别,把差别应用在原来的Dom树上,渲染出正确的UI界面。
在数据传输时,逻辑层会执行一次JSON.stringify
来去除掉setData
数据中不可传输的部分,以后将数据发送给视图层。同时,逻辑层还会将setData
所设置的数据字段与data
合并,使开发者能够用this.data
读取到变动后的数据。所以,为了提高数据更新的性能,开发者在执行setData
调用时,最好遵循如下原则:
2.1 不要过于频繁调用setData,应考虑将屡次setData合并成一次setData调用;
2.2 数据通讯的性能与数据量正相关,于是若是有一些数据字段不在界面中展现且数据结构比较复杂或包含长字符串,则不该使用setData
来设置这些数据;
2.3 与界面渲染无关的数据最好不要设置在data中,能够考虑设置在page对象的其余字段下
提高数据更新性能方式的代码示例
Page({
onShow: function() {
// 不要频繁调用setData
this.setData({ a: 1 })
this.setData({ b: 2 })
// 绝大多数时候可优化为
this.setData({ a: 1, b: 2 })
// 不要设置不在界面渲染时使用的数据,并将界面无关的数据放在data外
this.setData({
myData: {
a: '这个字符串在WXML中用到了',
b: '这个字符串未在WXML中用到,并且它很长…………………………'
}
})
// 能够优化为
this.setData({
'myData.a': '这个字符串在WXML中用到了'
})
this._myData = {
b: '这个字符串未在WXML中用到,并且它很长…………………………'
}
}
})
复制代码
在一个列表中,有n
条数据,采用上拉加载更多的方式,假如这个时候想对其中某一个数据进行点赞操做,还能及时看到点赞的效果
一、能够采用setData全局刷新,点赞完成以后,从新获取数据,再次进行全局从新渲染,这样作的优势是:方便,快捷!缺点是:用户体验极其很差,当用户刷量100多条数据后,从新渲染量大会出现空白期(没有渲染过来)
二、说到重点了,就是利用
setData
局部刷新
> a.将点赞的`id`传过去,知道点的是那一条数据, 将点赞的`id`传过去,知道点的是那一条数据
复制代码
<view wx:if="{{!item.status}}" class="btn" data-id="{{index}}" bindtap="couponTap">当即领取</view>
复制代码
> b.从新获取数据,查找相对应id的那条数据的下标(`index`是不会改变的)
> c.用setData进行局部刷新
复制代码
this.setData({
list[index] = newList[index]
})
复制代码
其实这个小操做对刚刚接触到微信小程序的人来讲应该是不容易发现的,不理解setData还有这样的写法。
2.4 切勿在后台页面进行setData
在一些页面会进行一些操做,而到页面跳转后,代码逻辑还在执行,此时多个webview
是共享一个js进程;后台的setData
操做会抢占前台页面的渲染资源;
视图层将事件反馈给逻辑层时,一样须要一个通讯过程,通讯的方向是从视图层到逻辑层。由于这个通讯过程是异步的,会产生必定的延迟,延迟时间一样与传输的数据量正相关,数据量小于64KB时在30ms内。下降延迟时间的方法主要有两个。
1.去掉没必要要的事件绑定(WXML中的bind
和catch
),从而减小通讯的数据量和次数; 2.事件绑定时须要传输target
和currentTarget
的dataset
,于是不要在节点的data
前缀属性中放置过大的数据。
4.1首次渲染
初始渲染发生在页面刚刚建立时。初始渲染时,将初始数据套用在对应的WXML片断上生成节点树。节点树也就是在开发者工具WXML面板中看到的页面树结构,它包含页面内全部组件节点的名称、属性值和事件回调函数等信息。最后根据节点树包含的各个节点,在界面上依次建立出各个组件。
在这整个流程中,时间开销大致上与节点树中节点的总量成正比例关系。于是减小WXML中节点的数量能够有效下降初始渲染和重渲染的时间开销,提高渲染性能。
简化WXML代码的例子
<view data-my-data="{{myData}}"> <!-- 这个 view 和下一行的 view 能够合并 -->
<view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
<text> <!-- 这个 text 一般是不必的 -->
{{myText}}
</text>
</view>
</view>
<!-- 能够简化为 -->
<view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
{{myText}}
</view>
复制代码
4.2 重渲染
初始渲染完毕后,视图层能够屡次应用setData
的数据。每次应用setData
数据时,都会执行重渲染来更新界面。初始渲染中获得的data和当前节点树会保留下来用于重渲染。每次重渲染时,将data
和setData
数据套用在WXML片断上,获得一个新节点树。而后将新节点树与当前节点树进行比较,这样能够获得哪些节点的哪些属性须要更新、哪些节点须要添加或移除。最后,将setData
数据合并到data
中,并用新节点树替换旧节点树,用于下一次重渲染。
在进行当前节点树与新节点树的比较时,会着重比较setData
数据影响到的节点属性。于是,去掉没必要要设置的数据、减小setData
的数据量也有助于提高这一个步骤的性能。
自定义组件的更新只在组件内部进行,不受页面其余不能份内容的影响;好比一些运营活动的定时模块能够单独抽出来,作成一个定时组件,定时组件的更新并不会影响页面上其余元素的更新;各个组件也将具备各自独立的逻辑空间。每一个组件都分别拥有本身的独立的数据、setData调用。
每一次事件监听都是一次视图到逻辑的通讯过程,因此只在必要的时候监听pageSrcoll
小程序启动加载性能
控制代码包的大小
分包加载
首屏体验(预请求,利用缓存,避免白屏,及时反馈
小程序渲染性能
避免不当的使用setData
合理利用事件通讯
避免不当的使用onPageScroll
优化视图节点
使用自定义组件