用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 查看内容

解决小程序渲染复杂长列表,内存不足问题

Rolan 2019-12-9 00:12

问题回顾:我们有一个列表展示页,是无限瀑布流式的,展示的元素我们封装成了单个组件,暂且叫它Item组件。这个瀑布流包含若干个Item组件,并且这个Item组件也比较复杂,包含各种展示样式(根据不同类型,大概有9种 ...

问题回顾:我们有一个列表展示页,是无限瀑布流式的,展示的元素我们封装成了单个组件,暂且叫它Item组件。这个瀑布流包含若干个Item组件,并且这个Item组件也比较复杂,包含各种展示样式(根据不同类型,大概有9种吧,反正渲染节点很多),在进行滑动的过程中,item大概加载30-40个以后,就会造成小程序内存不足而退出,蓝瘦香菇......【干货在最后,小程序代码片段奉上】

解决思路:

将超出屏幕一定部分的列表内的组件进行不渲染的处理(也就是用wx:if卸载掉组件),当到达渲染临界点时再开始渲染;保证每次少量的数据展示。

我们的项目中是保持15条Item,我们是每次分页请求5条,按照前5条,中间5条和后5条来划分,如果不在这个范围,则用一个等高度的骨架代替,并且卸载这些组件

初期实现方式(后面有更优化的方式)

使用曝光监听,当一个Item曝光时,记录Item高度,并放到数组里面,作为骨架的填充高度,如果已经记录了高度,则不再重复记录;曝光时向外传递一个当前渲染范围的中心值(比如当前Item所属页码,或者当前Item索引),以此进行处理;

这里有一点要注意,如果你的列表item组件比较复杂,需要在ready的时候将记录的高度设置为item最小高度,不然组件重新装载时会有一定的渲染时间,在临界点会造成跳屏【此处已经通过骨架组件解决,可以忽略,只是作为踩坑记录】

此时优化点

  • 为避免频繁setData和渲染,做了防抖函数,时间是600ms

此时缺点

  • 滑动特别快时,会出现白屏,是因为曝光监听是在组件里面,而超快速滚动时,组件没有装载进来,也无法进行曝光监听,所以无法触发,这里考虑用骨架组件进行二次监听曝光

优化迭代

  • 将骨架组件作为外壳套在Item外面(用slot),并对骨架进行监听曝光,可以解决上面缺点
  • 给骨架组件做一个常规骨架屏样式,而不是纯白色,看起来更优雅

继续发现问题

经过一系列的实践,上面的方案有些问题,其中最麻烦的就是,需要对外传递一个当前index,然后控制前后数据展示;这里对于每个用到skeleton组件的页面来说,都要重复的写一个方法来承接这个index,然后渲染页面对应的数据。

优化

依然是监听skeleton曝光,这里监听的方案变为出现在屏幕上下n屏的内容块进行展示,此范围外的内容块就卸载掉。

如图所示


核心代码

     // 修改了监听是否显示内容的方法,改为前后showNum屏高度渲染
     // 监听进入屏幕的范围relativeToViewport({top: xxx, bottom: xxx})
      let info = SystemInfo.getInfo() //获取系统信息
      let { windowHeight = 667 } = info.source.system
      let showNum = 2 //超过屏幕的数量,目前这个设置是上下2屏
      let listItemContainer = this.createIntersectionObserver()
      listItemContainer.relativeToViewport({ top: showNum * windowHeight, bottom: showNum * windowHeight })
        .observe(`#list-item-${this.data.skeletonId}`, (res) => {
        	// 此处来控制slot展示,详见代码片段
        })
       
复制代码

干货

话不多说,干货放后面,点击获取代码片段

最后,还是尽量减少节点数,优化代码

鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏
原作者: 宗仔GEG 来自: 掘金