我们经常使用setData方法来修改数据,从而达到更新页面的目的。但是当我们通过setData方法设置的数据过大时就会报如下错误。
vdSyncBatch 数据传输长度为 2260792 已经超过最大长度 1048576
这是因为setData设置的数据量是有限制的,单次设置的数据大小不得超过1024kb,否则就会出现如上错误。
而我们在一些列表页面中,每次上拉加载更多后,会习惯性的把之前存在的数据和新加载的数据合并后,一起通过setData提交来重新渲染页面。这样会留下隐患,当用户浏览的数据量达到一定程度时,就会出现如上错误。
解决方法
-
常规做法:分页加载后,每次都将全部的数据通过setData提交
data:{
// 数据源
list:[]
},getListData:function(){
// 本次加载的数据
let _list = [];
...
setData({
// 将之前的数据与本次加载的数据合并后,一起提交
list: this.data.list.concat(_list)
});
} -
改进后的做法:分页加载后,通过设置
list
指定位置的元素值,实现只提交新加载的数据,data:{
// 当前页数
pageNo:0,
// 数据源
list:[]
},getListData:function(){
// 本次加载的数据
let _list = [];
...
setData({
['list[' + pageNo + ']']: _list,
});
}
注意:改进后方案中的 list
与常规方案中的 list
已经不是同种数组。
常规方案中的 list
,是一维数组,直接存放 item,结构为:[{...},{...},{...},...]
。
而改进方案中的 list
是二维数组,每个子元素为一页 item 数据的集合,而子元素数组中的每个元素才是 item 数据,结构为:[[{..},{...},{...}],[{..},{...},{...}],[{..},{...},{...}],...]
,所以需要注意对wxml
中的列表结构进行修改。
// TODO: 记录一下总条数 this.loadedCount = this.loadedCount + data.list.length || 0; console.log(this.loadedCount, "总数组长度"); // 分页条件 if (this.loadedCount < data.total) { // 页码累加 pageNo++; } else { // 分页已结束 isFinish = true; // 拼接还原截取的天数并清空 orderList = orderList.concat(this._slicedArr); this._slicedArr = []; } // 更新数据 this.setData({ ["OrderConfig.isFinish"]: isFinish, ["OrderConfig.pageNo"]: pageNo, ["OrderConfig.isLoading"]: false, orderList, //如果数据加载完毕 -1 否则为pageNo-2(因为是先++,并且页数从1开始,索引应该为0) [`dayList[${isFinish ? pageNo - 1 : pageNo - 2}]`]: data.list, daytotal: data.total, }); console.log(dayList);
此处作者使用total作为判断条件的 拆分之后获取不到总条数需要单独记录
因为pageNo为1开始所以做了个判断 可参考
优化实践
纸上得来终觉浅,理论还得去实践~
1. 删掉渲染层用不到的数据,全都改到 this
或下其他方式 --- 难度系数 ⭐️
**2. 将频繁更新的页面元素封装为组件,大多数场景我们都是在组件化开发,这点几乎没有难度,只不过需要额外留意"频繁更新"这个关键词,看有没有漏掉的 ** --- 难度系数 ⭐️
3. 检查后台运行的 setData,包括不在可视窗口内的,改成进入后台后暂停 setData,比如轮播,倒计时等场景可能为高发地段 --- 难度系数 ⭐️⭐️
鉴于人工检查、分析较为耗费精力,加一颗星
4. 减少调用 setData ,合并 setData --- 难度系数 ⭐️⭐️⭐️⭐️⭐️
看着不难做到,为啥五颗星?
由于函数式编程和函数单一职责原则,为了更好的可读性和可维护性,我们的代码往往要实现低耦合,这意味着某些场景我们不得不把 setData 分散到各个函数,而不能把它们糅杂到一起,造成的问题显而易见,每个 setData 都会产生通信消耗,那将浪费不少性能,能够完美的在性能和可维护性之间做好平衡是不容易的,大多数情况我们都是取可维护性而舍性能。
5. setData 只传入数据发生变化的字段,使用数据路径形式替换直接更新某个对象或数组 --- 难度系数 ⭐️⭐️⭐️⭐️⭐️
分页列表使用二维数组实现; 避免使用 this.setData(...obj)
,...
本身就是遍历迭代器的操作,比 forEach
性能还要差一些,如果仅仅是 obj
里的属性变化,使用数据路径形式替代,只更新必要字段,而且...
也不直观;
除此之外,还有很多不易发现或者不易判断是否发生变化的属性,在开发过程中不可避免地会被遗漏掉,全都考虑的面面俱到的话整个开发过程会极为复杂,在setData
一个属性时需要留意该属性目前可能是处于一个什么样的状态,做出判断,甚至得为了只更新变化的数据而多写很多逻辑,这样虽然可能性能有所提升,但是对于开发者来说极不友好,写个 setData
都得思前顾后。。。
还有些是我们为了更好的可读性、代码的简洁性主动忽略掉这点的。
因此,这样被重复渲染的数据在大多数项目中都绝不在少数,只是由于无法量化,且在当今的一些高性能手机上表现也过得去,所以大家也就没太在意,但是优化的空间肯定是存在的,且非常大,只不过优化成本较高,费心费力,所以此题也给 5 颗星。