微信小程序 --- 小程序优化相关

1. 减少this.setData的操作, 尽量将多次操作合并为一次(避免频繁操作引起CPU占用过高导致卡顿)

this.setData({ a: 1 })
this.setData({ b: 2 })
// 可优化为
this.setData({ a: 1, b: 2 })

2. 减少this.setData中的数据量(无关的数据量,在数据过大时会引起内存溢出)

// 接口返回数据
let a = {
    name: '豆浆',
    age: 11,
    other: '与渲染无关的字符串'
}
// 修改非实际更新所需数据
let a = {
    name: '豆浆',
    age: 11
}


// 可优化为
this.setData({ a })

3. 尽量将逻辑放在后台实现,减少前端代码量

1、意义
在这里插入图片描述

  • 减少前端代码量。对于大型小程序项目至关重要,不仅因为小程序代码包大小有限,若代码包过大,会直接影响小程序整体性能和页面切换速度
  • 利于多端统一。复杂业务由后台统一实现,前端仅做简单处理和展示,有效避免因各端开发对业务理解的差异,导致各端页面实际展现效果不一致
  • 降低人力成本。业务逻辑统一在后台实现,避免各前端重复开发。测试童鞋可重点关注后台逻辑准确性,无需分别对各端进行详细的业务逻辑验证
  • 增强项目可控性。与 h5 不同,小程序发版难度大、周期长、线上多版本并存,一旦出现紧急需求或业务问题,前端很难快速解决

终极目标:类似需求前端只开发一次,后期迭代由后端开发完成后直接上线。

2、改造过程
在这里插入图片描述
逻辑后移过程
参考规范:

  • 仅用于一处文案展示。仅用于在固定位置展示文案,没有其他模块用到相关数据,建议后台直接下发文案
  • 用于标识。用于标识某种类型、状态,建议将相同类型的字段合并为一个字段。
  • 用于复合场景。既要展示文案,又要用于其他业务逻辑计算。先看看相关模块是否可以一起改造,如若不能,建议后台下发关键数据,前端做简单文案拼接处理

4. 列表数据中,局部数据更新别使用直接清空填充,会出现白屏等情况,比方点赞的局部更新,获取其下标单独更新局部数据

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

5. 合理使用小程序组件

自定义组件的更新只在组件内部进行,不会影响页面其他元素。因为各个组件具有独立的逻辑空间、数据、样式环境及 setData 调用。 基于自定义组件的 Shadow DOM 模型设计,我们可以将页面中一些需要高频执行 setData 更新的功能模块(如倒计时、进度条等)封装成自定义组件嵌入到页面中。 当这些自定义组件视图需要更新时,执行的是组件自己的 setData,新旧节点树的对比计算和渲染树的更新都只限于组件内有限的节点数量,有效降低渲染时间开销。
在这里插入图片描述
当然,并不是使用自定义组件越多会越好,页面每新增一个自定义组件, Exparser 需要多管理一个组件实例,内存消耗会更大。因此要合理的使用自定义组件,同时页面设计也要注意不滥用标签


6.控制小程序包大小,减少下载时间

常见的控制代码包大小的方法如下:

  • 精简代码,清除无用代码
  • 减少在代码包中直接嵌入的资源文件
  • 图片放在cdn,使用适当的图片格式
// 比方平常最常见的this.data的数据

data: {
    name: '豆浆',
    age: 11,
    job: '搬砖工'
}
// 优化前
this.setData({
    name: this.data.name,
    age: this.data.age,
    job: this.data.job
})
// 或者
let name = this.data.name;
let age= this.data.age;
let job= this.data.job;

this.setData({ name, age, job });

// 优化后 利用es6
let { name, age, job } = this.data;
this.setData({ name, age, job });

7.当项目过大需要分包,合理利用分包预加载,减少分包loading情况,分包预加载会影响当前页面渲染时间,要合理使用


8.小心后台页面的js

小程序中可能有n个页面,所有的这些页面,虽然都拥有自己的webview(渲染层), 但是却共享同一个js运行环境。也就是说,当你跳到了另外一个页面(假设是B页面),本页面(假设是A页面)的定时器等js操作仍在进行,并且不会被销毁,并且会抢占B页面的资源。
在h5的环境中,当我们跳转到其他页面,老页面的js环境会被自动销毁,定时器什么都被销毁掉了,因此我们不需要关心老页面中,还有哪些js代码可能还会执行。但是在小程序中,我们必须手动的“清理”掉这样的代码


9. 小心onPageScroll

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


10. 小心获取节点位置

在h5 中的环境中,为了实现懒加载、下拉加载,我们不得不去获取节点的位置。
为啥说不得不,是因为我们本可以用新的api ——intersectionObject去轻松实现(google等主流浏览器都已经支持了),但是微信的内置X5浏览器很遗憾的不支持。
没想到,在小程序的环境中,微信竟然良心发现,支持intersectionObject api, 因此获取节点的信息,尽量还是用这api 吧


11.在路由跳转前就发起请求

可使用事件订阅的方式提前触发事件(比方onfire.js)
onfire.js下载地址: https://www.bootcdn.cn/onfire.js/
onfire.js使用方式: https://www.oschina.net/p/onfire-js

参考文章;

https://blog.csdn.net/sinat_27612147/article/details/80798452
https://developers.weixin.qq.com/community/develop/doc/0008c0b52183d0d9e127da95f5b006
http://www.xcxwo.com/component/view/28dc0cd2a0532b75bdcd092e82d64a7b


12. 优化页面结构,减少不必要的节点

  • 虽然一般情况下不需要操作节点,但在某些特殊情况,比方懒加载需要获取节点的情况,本身操作节点已经很耗费性能,若再加上多余的节点会加剧这个情况
  • 页面初始渲染时,渲染树的构建、计算节点几何信息以及绘制节点到屏幕的时间开销都跟页面节点数量成正相关关系,页面节点数量越多,渲染耗时越长。
  • 每次执行 setData 更新视图,WebView JS
    线程都要遍历节点树计算新旧节点数差异部分。当页面节点数量越多,计算的时间开销越大,减少节点树节点数量可以有效降低重渲染的时间开销。

13.预判预加载

在这里插入图片描述
目的:提前加载目标页面请求,大幅缩短目标页面白屏时间。
原理:预测用户从页面 A 进入页面 B 的可能性较大,在页面 A 内主动调用页面 B 的预加载处理函数,提前加载请求。进入页面 B 后,使用预加载数据渲染首屏
缺点:

  • 对数据时效性要求较高的场景不适用
  • 预加载后,用户不一定会打开目标页面 B,可能造成资源浪费

14.合理利用缓存

缓存是一种备受青睐的性能优化方法。不仅可以减少请求数,降低弱网场景空窗率,合理利用缓存甚至能使首屏耗时缩短至少 30%以上。
它适用于数据稳定性强,时效性要求低的场景,如图片、字体、配置文件等。
像购物车这种,商品列表变化比较频繁的场景能否使用缓存?
答案是肯定。


15. 移除 scroll-view

scroll-view 组件是一种滚动视图容器,它提供了一个名为 scroll-into-view 的功能,可以使视图滚动到指定元素,为方便描述,下文简称定位功能。

1、背景

购物车很多场景用到定位功能,小程序不支持 DOM 操作,使我们不得不使用 scroll-view 这个大型组件。
但是,scroll-view 组件存在较多性能问题:

  • 与 view 组件相比,scroll-view 占用内存和 cpu 资源更多。可通过 Performance monitor 观察
    cpu、内存使用情况
  • 滚动体验比页面自带滚动效果差
  • 在一些低端机或页面节点总数较多的情况下,scroll-view 组件很容易引起掉帧、白屏
    节点复杂度越大,总节点数越多,scroll-view 暴露的性能问题越明显。 为了优化滚动体验,减轻 cpu和内存压力,我们移除了这个组件的引用。

2、难点
想要移除 scroll-view,必须找到定位功能的替代方案。在微信基础库版本 2.7.3 以上版本,可使用 wx.pageScrollTo 的定位到锚点功能,对于 2.7.3 以下版本,需要自己编码实现。
示例代码:

_pageScrollTo ({ partten }) {
    if (this.createSelectorQuery && wx.pageScrollTo) {
        const query = this.createSelectorQuery()
        query.selectViewport().scrollOffset()
        query.select(partten).fields({ rect: true })
        query.exec(function (res) {
            if(res) {
                const windowHeight = (wx.getSystemInfoSync() || {}).windowHeight || 619const offsetY = windowHeight * 0.35// 目标位置距离窗口上边界的偏移量const _scrollTop = res[0].scrollTop // 滚动条竖直滚动位置const _top = res[1].top // 目标节点上边界坐标const scrollTop = _scrollTop + _top - offsetY
                wx.pageScrollTo({ scrollTop, duration: 0 })
            }
        })
    }
}

建议关闭 wx.pageScrollTo 的滚动动画。在一些低端机器上,滚动过程中页面部分区域会白屏,且不会自动恢复。另外,基础库 2.6.4 以下版本,滚动过程中 fixed 元素会闪烁。

3、效果对比
移除 scroll-view 之后,列表滚动过程中几乎不会白屏。下面是 scoll-view 移除前后效果图。
在这里插入图片描述


15. 自动分页渲染

背景

早期,为缩短白屏时间,购物车使用了分屏渲染技术,把数据分为首屏和非首屏两部分,首屏渲染完成后再渲染非首屏数据。
分屏渲染最大问题在于,一旦非首屏数据量过大,渲染耗时会很长,让用户等待很长时间,最糟的情况可能引起页面假死,严重影响用户体验。
随着业务增长,这个问题带来的影响已经越来越明显,因此我们开始考虑改用分页技术

1、技术选型
难点:
业务复杂。短期内无法实现分页请求数据,只能实现纯前端分页
数据量大。每个商品不仅包含主品的各项信息,还可能附加与商品结构类似的赠品、换购商品等
商品列表顺序动态改变。例如修改商品促销,该商品可能由列表第一项变成最后一项,操作完成后还要定位到该商品
在这里插入图片描述
技术选型
综合考虑各种业务场景和各项分页技术的特点,最终决定采用自动分页渲染技术。

2、基本思想

  • 一次性请求全部数据
  • 将数据分成若干页,每次只渲染一页
  • 上一页渲染完成后,自动循环渲染下一页

3、循环渲染实现方案对比

  • 通过 setData 递归。setData 的回调函数触发时立刻渲染下一页。缺点是会导致 UI 线程一直忙碌,用户操作响应变慢。
  • 利用 setTimeout。setData 回调函数触发时,用 setTimeout 延迟一段时间再渲染下一页。缺点是执行时间不可控。
  • 利用时间分片。通过 requestAnimationFrame(简称 raf)实现。调用 raf
    之后,浏览器在准备渲染下一帧前会调用你传给 raf 的回调函数。按照帧率为 60fps 来计算,每一帧的间隔在 16.6ms 左右。

通过多次实验对比,最终我们选择时间分片模式。

4、示例
Demo: https://developers.weixin.qq.com/s/XJEDb3mP7Kex
原理: 用 raf 代替定时器,每次 setData 完成后,延迟 16.6ms 左右,再渲染下一页
实现思路:每次 setData 时触发 wxs 事件监听器,在 wxs 事件处理函数中调用 raf,raf 回调执行时调用逻辑层函数渲染下一页
流程图如下:
在这里插入图片描述
raf demo 流程图
5、效果对比
下面是使用分屏渲染(左图)与自动分页渲染(右图)的效果图。可操作时间缩短 50%+
在这里插入图片描述


16. 压缩图片

图片压缩地址: https://tinypng.com/
小程序中图片占据的整体的大部分空间,所以尽可能的较少图片体积要是很重要的


17. 模块化开发

小程序也是js, 所以模块化开发时理所当然可以的,自带ES6自动转换,不管多细小的东西都可以封装城一个模块,增加每一个代码块的复用性,积小成多,慢慢的就减少了很多多余的代码了,像官方自带的api也可以封装比方弹窗提醒


18. 公共CSS

js可以优化,css当然也可以,根据设计图找到所有共同点,将其写在公共CSS中,减少多余的CSS代码,但不可以滥用,因为若放在app.wxss中会全局引用,那么多余的部分就会导致浪费了


19. 列表资源加载图片资源避免高清图,会引起内存占用过高崩溃

有部分场景需要加载高清图,但在列表展示用,可以使用压缩资源,减少cpu占用率,可以后台返回两种链接,一种为高清图访问链接,一种为压缩后的链接

这里提供一下腾讯云的方式
开通数据万象
绑定存储桶
点击数据万象 -> 存储桶管理 -> 图片处理 ->样式管理
Guetzli图片压缩开启
样式管理 -> 添加样式 -> 根据需求设置
点击预览,会进行页面跳转,获取URLhttp://watermark2-1252106211.image.myqcloud.com/preview.png?imageMogr2/thumbnail/500x/interlace/0
将预览后地址栏的地址进行图片名称替换即可,若需更改宽高,以上面例子为例。替换500x中的500即可
在这里插入图片描述

参考文章列表

https://mp.weixin.qq.com/s/Iz3FheStNj6B_Al1bjErYg
https://juejin.im/post/5d4d2b9f5188255d84600a12#heading-2
https://mp.weixin.qq.com/s/aAzwYA_RnKSt-y8xDHTtPQ
https://mp.weixin.qq.com/s/1akI1YhK1zGqxPTa50n65A
https://juejin.im/post/5bdbc28e51882516eb55dd1d#heading-1
https://blog.csdn.net/css_666/article/details/82688651

发布了102 篇原创文章 · 获赞 75 · 访问量 44万+

猜你喜欢

转载自blog.csdn.net/sinat_19327991/article/details/105281003