type
status
date
slug
summary
tags
category
icon
password
某天闲着无聊想练一下手速,去上拉一个小程序项目中一个有1万多条商品数据的列表。在数据加载到1000多条后,是列表居然出现了白屏。看了一下控制台:

‘Dom limit exceeded’,dom数超出了限制, 不知道微信是出于什么考虑,要限制页面的dom数量。
一.小程序页面限制多少个wxml节点?
写了个小dome做了个测试。
listData的数据结构为:
页面渲染效果:

1.dome1

2.dome2,删除了不必要的dom嵌套


二.列表页面优化
1.减少不必要的标签嵌套
由上面的测试dome可知,在不影响代码运行和可读性的前提下,尽量减少标签的嵌套,可以大幅的增加页面数据的列表条数,毕竟公司不是按代码行数发工资的。如果你的列表数据量有限,可以用这种方法来增加列表渲染条数。如果数据量很大,再怎么精简也超过2万的节点,这个方法则不适用。
2.优化setData的使用
如
图五所示,小程序setDate的性能会受到setData数据量大小和调用频率限制。所以要围绕减少每一次setData数据量大小,降低setData调用频率进行优化。(1)删除冗余字段
后端的同事经常把数据从数据库中取出就直接返回给前端,不经过任何处理,所以会导致数据大量的冗余,很多字段根本用不到,我们需要把这些字段删除,减少
setDate的数据大小。(2)setData的进阶用法
通常,我们对data中数据的增删改操作,是把原来的数据取出,处理,然后用
setData整体去更新,比如我们列表中使用到的上拉加载更多,需要往listData尾部添加数据:这样会导致
setDate的数据量越来越大,页面也越来越卡。setDate的正确使用姿势setDate修改数据 比如我们要修改数组listData第一个元素的isDisplay属性,我们可以这样操作:
如果我们想同时修改数组
listData中下标从0到9的元素的isDisplay属性,那要如何处理呢?你可能会想到用for循环来执行setData:那么这样就会导致另外一个问题,那就是
listData的调用过于频繁,也会导致性能问题,正确的处理方式是先把要修改的数据先收集起来,然后调用setData一次处理完成:这样我们就把数组
listData中下标从0到9的元素的isDisplay属性改成了false。setDate往数组末尾添加数据 如果只添加一条数据
如果是添加多条数据
至于删除操作,还没有找到更好的方法,不知道大家有什么方法可以分享吗?
三.使用自定义组件
可以把列表的一行或者多行封装到自定义组件里,在列表页使用一个组件,只算一个节点,这样你的列表能渲染的数据可以成倍数的增加。组件内的节点数也是有限制的,但是你可以一层层嵌套组件实现列表的无限加载,如果你不怕麻烦的话
四.使用虚拟列表
经过上面的一系列操作后,列表的性能会得到很大的提升,但是如果数据量实在太大,
wxml节点数也会超出限制,导致页面发生错误。我们的处理方法是使用虚拟列表,页面只渲染当前可视区域以及可视区域上下若干条数据的节点,通过isDisplay控制节点的渲染。- 可视区域上方:
above
- 可视区域:
screen
- 可视区域下方:
below

1.listData数组的结构
使用二维数组,因为如果是一维数组,页面滚动需要用
setData设置大量的元素isDispaly属性来控制列表的的渲染。而二维数组可以这可以一次调用setData控制十条,二十条甚至更多的数据的渲染。2.必要的参数
3.wxml的dom结构
4.获取列表第一层dom的px高度
5.页面滚动时间节流
6.页面滚动事件处理
经过上面的处理后,页面的
wxml节点数量相对稳定,可能因为可视区域数据的index计算误差,页面渲染的数据有小幅度的浮动,但是已经完全不会超过小程序页面的节点数量的限制。理论上100万条数据的列表也不会有问题,只要你有耐心和精力一直划列表加载这么多数据。7.待优化事项
- 列表每一行的高度需要固定,不然会导致可视区域数据的index的计算出现误差
- 渲染玩列表后往回来列表,如果手速过快,会导致above,below区域的数据渲染不过来,会出现短暂的白屏,白屏问题可以调整
prepareNumthrottleTime两个参数改善,但是不能完全解决(经过测试对比发现,即使不对列表进行任何处理,滑动速度过快也会发生短暂白屏的情况)。
- 如果列表中有图片,above,below区域重新渲染时,图片虽然以经缓存在本地,不需要重新去服务器请求,但是重新渲染还是需要时间,尤其当你手速特别快时。可以根据上面的思路,
isDisplay时只销毁非<image>的节点,这样重新渲染就不需要渲染图片,但是这样节点数还是会增加,不过应该能满足大部分项目需求了,看自己项目怎么取舍。
五.使用自定义组件和虚拟列表的对比。
虽然不知道为什么,但是直觉告诉我使用自定义组件性能会相对差一点。为了对比两种方法的优劣,使用了Trace工具对一个5000条带图片数据进行了性能测试。
内存占用对比:
自定义组件内存占用情况:
.png?table=block&id=452d94b5-d406-465f-9464-2e27b30964df&t=452d94b5-d406-465f-9464-2e27b30964df&width=648&cache=v2)
虚拟列表内存占用情况:
.png?table=block&id=3f8b49a5-8c92-4774-b39d-77f354c55d59&t=3f8b49a5-8c92-4774-b39d-77f354c55d59&width=648&cache=v2)
对比可以看出,因为组件在上拉加载时,组件是没有销毁的,导致数据量逐渐增多。而虚拟列表在增加数据的同时,也会销毁相同数量的数据,所以内存占比会稳定在一个数量。具体到这个测试dome,5000条数据使用自定义组件,最后占用2000MB的内存,而虚拟列表稳定在700MB。
setData后重新渲染所用的时间对比:
自定义组件重新渲染耗时:
.png?table=block&id=9cefe92d-ba68-4b01-9907-716cc47f391e&t=9cefe92d-ba68-4b01-9907-716cc47f391e&width=643&cache=v2)
虚拟列表重新渲染耗时:
.png?table=block&id=4c0c0f3f-67a2-4ccc-af39-e5345471c892&t=4c0c0f3f-67a2-4ccc-af39-e5345471c892&width=648&cache=v2)
从测试结果可以看出,无论是耗时的次数分布,还是最大耗时,最小耗时,虚拟列表都优于自定义组件
最后附上虚拟列表的github地址,如果对您有帮助,记得给个小星星哦