回复 刷新

暂无评论

浅谈微信小程序性能的优化技巧

微信小程序如果想要优化性能,有关键性的两点:提高加载性能和提高渲染性能。

一、提高加载性能

当用户点击小程序后发生了什么?

资源准备(代码包下载) —— 业务代码注入和渲染 —— 异步请求数据

上面的三个状态,我们经常遇到,它们分别对应小程序的下面三个状态:

  1. 有三个点的白屏阶段: 下载代码包的阶段
  2. 没有三个点的白屏: 业务代码注入和渲染的阶段
  3. 加载中: 业务代码中异步请求数据

总的来说,小程序呈现到用户面前,实际上经历了下面两个阶段:运行环境的加载,下载代码包启动小程序。

运行环境预加载:这步是微信做的。微信会在用户打开小程序之前就已经准备好环境,用户点击小程序入口后,直接下载小程序的代码包即可。

下载代码包启动小程序,小程序代码包里面的代码,不是小程序的源代码,而是编译、压缩、打包之后的代码包。

下图中,左侧的“预加载”对应的是运行环境的预加载,右侧的“小程序启动” 对应的是下载代码包启动小程序。
 1.png

 小程序提供的运行环境,分为逻辑层(AppService)和 视图层(webView),逻辑层是执行javascript的地方,视图层是渲染页面的地方。当小程序的代码包下载完毕后,业务代码分别注入逻辑层和渲染层。

提升加载性能的最最最关键性一点是,控制包的大小,这个也是微信官方的说法。

提升体验最直接的方法是控制小程序包的大小,基本上可以说,1M的代码包,下载耗时1秒左右。

控制包大小的措施:

  1. 压缩代码,清理无用的代码
  2. wxss 覆盖率较高,较少或没有引入未被使用的样式。按需引入 wxss 资源,如果小程序中存在大量未使用的样式,会增加小程序包体积大小,从而在一定程度上影响加载速度
  3. 图片放在cdn
  4. 避免将不会被使用的文件打包进去
  5. 采用分包策略
  6. 分包预加载
  7. 独立分包(版本要求有点高)

除了上面讲的控制包的大小,对异步请求的优化也很重要。

对异步请求的优化

  1. onLoad 阶段就可以发起请求,不用等ready
  2. 请求结果放在缓存中, 下次接着用
  3. 请求中可以先展示骨架图

先反馈,再请求。比如说,点赞的按钮,可以先改变按钮的样式,再发起异步请求。

二、提升渲染性能

setData 干了啥?每调用一次setData, 都是逻辑层向渲染层的一次通讯,这个通信还不是直接传给webView, 而是通过走了native层,通讯的开销很大。

渲染层收到通讯后,还需要重新渲染出来,所以,一次setData带来两次开销:通信的开销 + webview更新的开销。

setData工作原理:

小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。

而 evaluateJavascript 的执行会受很多方面的影响,数据到达视图层并不是实时的。

由于小程序运行逻辑线程与渲染线程之上,setData的调用会把数据从逻辑层传到渲染层,数据太大会增加通信时间。

2.png

在数据传输时,逻辑层会执行一次JSON.stringify来去除掉setData数据中不可传输的部分,之后将数据发送给视图层。

同时,逻辑层还会将setData所设置的数据字段与data合并,使开发者可以用this.data读取到变更后的数据:

  1. 减少setData的数据量:如果一个数据不能会影响渲染层,则不用放在setData里面

  2. 合并setData的请求,减少通讯的次数

  3. 列表的局部更新

在一个列表中,有n条数据,采用上拉加载更多的方式,假如这个时候想对其中某一个数据进行点赞操作,还能及时看到点赞的效果。此时,可以采用setData全局刷新,点赞完成之后,重新获取数据,再次进行全局重新渲染,这样做的优点是:方便,快捷!缺点是:用户体验极其不好,当用户刷量100多条数据后,重新渲染量大会出现空白期(没有渲染过来)

如果采用局部刷新,将点赞的id传过去,知道点的是那一条数据,重新获取数据,查找相对应id的那条数据的下标(index是不会改变的),用setData进行局部刷新

this.setData({
list[index] = newList[index]
})

3、小心后台页面的js
  
小程序中可能有n个页面,所有的这些页面,虽然都拥有自己的webview(渲染层), 但是却共享同一个js运行环境。

也就是说,当你跳到了另外一个页面(假设是B页面),本页面(假设是A页面)的定时器等js操作仍在进行,并且不会被销毁,并且会抢占B页面的资源。

在h5的环境中,当我们跳转到其他页面,老页面的js环境会被自动销毁,定时器什么都被销毁掉了,因此我们不需要关心老页面中,还有哪些js代码可能还会执行。但是在小程序中,我们必须手动的“清理”掉这样的代码。

4、小心onPageScroll

pageScroll 事件,也是一次通讯,是webview层向js逻辑层的通讯。这次通讯也是开销较大,如果考虑到这个事件被频繁的调用,回调函数如果有复杂的setData的话,性能就会很差了。

5、尽可能使用小程序组件

自定义组件的更新只在组件内部进行,不受页面其他部分内容的影响;比如一些运营活动的定时模块可以单独抽出来,做成一个定时组件,定时组件的更新并不会影响页面上其他元素的更新;各个组件也将具有各自独立的逻辑空间。每个组件都分别拥有自己的独立的数据、setData调用。

  • 35
  • 0
  • 0