微信小程序性能优化总结

6,417 阅读8分钟

对微信小程序进行性能优化,主要可以从两大方面进行分析:性能扫描工具和代码优化。

一、使用性能扫描工具

微信小程序提供了一个“体验评分”的工具插件,可以使用它获得微信小程序的一些性能数据和明显的缺陷,进而根据报告进行相应的优化。

image.png

image.png

同时,为了方便开发者能够及时发现小程序的体验问题,从开发者工具 1.02.1811150 版本起支持体验评分的 “自动运行” 功能。一旦发现体验分数低于 70 分时,系统会在 console 面板打印一个 warning 信息提示开发者。

image.png

然后,根据效果图的分析报告,查看需要优化的细项,并根据说明一一进行优化。常见的优化点包括:

  • 应避免出现任何 JavaScript 异常:因为出现JavaScript异常可能导致小程序的交互无法进行下去;
  • 所有请求的耗时不应太久:因为请求耗时太长会让用户一直等待甚至离开,应当优化好服务器处理时间、减小回包大小,让请求快速响应;
  • 避免将未绑定在 WXML 的变量传入setData:因为setData操作会引起框架处理一些渲染界面相关的工作,而一个未绑定的变量意味着与界面渲染无关,传入setData会造成不必要的性能消耗;
  • 避免渲染界面的耗时过长:因为渲染界面的耗时过长会让用户觉得卡顿,体验较差;
  • 避免执行脚本的耗时过长:因为执行脚本的耗时过长会让用户觉得卡顿,体验较差,出现这一情况时,需要确认并优化脚本的逻辑;
  • 网络请求使用 HTTPS:因为使用 HTTPS,可以让你的小程序更加安全,而 HTTP 是明文传输的,存在可能被篡改内容的风险;
  • 避免过大的 WXML 节点数目:建议一个页面使用少于 1000 个 WXML 节点,节点树深度少于 30 层,子节点数不大于 60 个。一个太大的 WXML 节点树会增加内存的使用,样式重排时间也会更长;
  • 及时回收定时器:因为定时器是全局的,并不是跟页面绑定的,所以当页面因后退被销毁时,定时器应注意手动回收;

除此之外,微信小程序官方还给出了如下一些要求:

  • 代码包不包含插件大小超过 1.5 M:小程序代码包单个包大小限制为2M。因此我们建议开发者在开发时,如果遇到单包体积大于1.5M的情况,可以采取分包的方式,把部分代码拆分到分包去,降低单个包的体积,提升小程序的加载速度
  • 引用插件大小超过 200 K:小程序插件的大小是会算进小程序代码包2M体积限制中的。因此当我们发现开发者引用的插件体积大于200K时,会对开发者予以提示,避免出现上传阶段提示代码包体积超限。
  • 图片和音频资源大小超过 200 K:小程序代码包里可以存放一些必要的静态资源(例如tabbar的icon等),不过静态资源体积过大也会影响小程序代码包加载速度。因此我们建议图片、音频等静态资源体积大小超过200K时,将它们上传到CDN,用URL引入会是个更好的选择。
  • 主包存在仅被其他分包依赖的JS:当主包里存在一些JS文件只会被分包使用(而主包自己不使用)时,我们建议把这些JS文件从主包中拆分出去,放到对应的分包里,从而优化主包的加载速度。
  • 主包存在仅被其他分包依赖的组件:当主包里存在一些组件只会被分包使用(而主包自己不使用)时,我们建议把这些组件从主包拆分出去,并且可以使用 分包异步化 这个特性加载这些组件,从而优化主包的加载速度。
  • 存在无使用的插件:如果有无使用的插件,请将其从 app.json 中去除。不然它会占用代码包体积,也会延迟代码包加载的时间。
  • 存在无使用的组件:如果在对应页面JSON的 usingComponents 里声明的组件但是没有使用,请将其从 usingComponents 里去除。

二、其他常见优化

2.1 启动优化

针对启动性能优化,可以从以下几个方面着手: 控制代码包大小

  • 开启开发者工具中"上传代码时自动压缩";
  • 及时清理无用代码和资源文件;
  • 减少代码包中的图片等资源文件的大小和数量;

分包加载

  • 将小程序中不经常使用的页面放到多个分包内,主包是保留最常用的核心页面;启动时只加载主包,使用时按需下载分包;
  • 使用分包加载会出现用户首次进入分包页面时需要进行分包的下载和注入,造成页面切换的延迟;开发者可使用分包预下载,预先配置页面可能会跳转到的分包,框架在进入页面后根据配置进行预下载;

独立分包

  • 从分包页面启动时,必需要先依赖于主包的下载和注入,启动速度受主包限制;使用独立分包,从独立分包页面启动,只下载和注入分包就可以打开页面;

2.2 首屏加载的体验优化建议

  • 提前请求:异步数据请求不需要等待页面渲染完成(onLoad 阶段就可以发起请求,不用等ready);
  • 利用缓存:利用storage API对异步请求数据进行缓存,二次启动时先利用缓存数据渲染页面,而下拉刷新或者缓存过期才更新数据;
  • 避免白屏:先展示页面骨架和基础内容;
  • 及时反馈:即时地对需要用户等待的交互操作给出反馈,避免用户以为小程序无响应;

2.3 避免不当使用setData

当setData的数据过大时,通讯方面会带来巨大的消耗,大部分人面对长列表滚动的时候,一开始的处理方式都是这样的,如果数据不多,只有几页可能不会太暴露问题;但当页数过多,几十页甚至上百页的情况,list的数据会越来越大,每次setData的数据就会越来越多,因而每次页面重新渲染的节点就会越来越多,从而导致滚动到后面,加载越来越慢。另外,由于小程序的视图渲染层和数据逻辑处理层是分开的,不是在同一个线程上面的,从用户触发页面交互,到处理数据逻辑,最后呈现页面,数据到视图是需要传输的,因而小程序本身对数据大小也有限制,不能超过1M。

2.4 存在短时间内发起太多图片请求

一次性发送了过多的图片请求,导致了同一时间发起了过多的http请求,http连接是非常耗时的,尤其是一次性发起这么多,并且一次性发起的http链接也是有限制的,比如chrome浏览器就限制一次性最多6个。所以在渲染页面时,不在视图范围内的图片不要不加载,只有元素出现在视图范围内了才渲染。

要实现这一效果,我们可以通过 getBoundingClientRect() 获取元素的位置,然后与页面滚动位置进行比较,如果出现在视图内就加载显示图片。具体实现上,我们可以失业微信提供的 IntersectionObserver 对象,IntersectionObserver 对象可以用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见,示例如下。

let data = list;
<img class="img-{{index}}" wx:for="{{data}}"></img>
data.forEach((item,index)=>{
  this.createIntersectionObserver().relativeToViewport.observe(`.img-${index}`,res=>{
    if (res.intersectionRatio > 0){
      this.setData({
        item.imgShow:true
      })
    }
  })
})

2.5 在列表渲染中巧用key值

在列表渲染过程中,巧用key值能够提升列表渲染性能。在小程序开发中,页面的渲染主要分为以下几步:

  1. 将wxml结构的文档构建成一个vdom虚拟数。
  2. 页面有新的交互,产生新的vdom数,然后与旧数进行比较,看哪里有变化了,做对应的修改(删除、移动、更新值)等操作。
  3. 最后再将vdom渲染成真实的页面结构。

key值的作用就在第二步,当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

2.6 避免使用onPageScroll不当

不正确的使用onPageScroll,可能会带来重复渲染的问题。因此,使用onPageScroll时,应注意以下几点:

  • 只在必要的时候监听pageScroll事件;
  • 避免在onPageScroll中执行复杂逻辑;
  • 避免在onPageScroll中频繁调用setData;
  • 避免频繁查询节点信息(SelectQuery);