微信小程序 setData数据量过大的解决与分页加载的实现

我们经常使用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 颗星。

相关推荐
希忘auto2 天前
详解Redis的常用命令
redis·1024程序员节
yaosheng_VALVE2 天前
探究全金属硬密封蝶阀的奥秘-耀圣控制
运维·eclipse·自动化·pyqt·1024程序员节
dami_king2 天前
SSH特性|组成|SSH是什么?
运维·ssh·1024程序员节
一个通信老学姐7 天前
专业125+总分400+南京理工大学818考研经验南理工电子信息与通信工程,真题,大纲,参考书。
考研·信息与通信·信号处理·1024程序员节
sheng12345678rui7 天前
mfc140.dll文件缺失的修复方法分享,全面分析mfc140.dll的几种解决方法
游戏·电脑·dll文件·dll修复工具·1024程序员节
huipeng9268 天前
第十章 类和对象(二)
java·开发语言·学习·1024程序员节
earthzhang20218 天前
《深入浅出HTTPS》读书笔记(19):密钥
开发语言·网络协议·算法·https·1024程序员节
爱吃生蚝的于勒9 天前
计算机基础 原码反码补码问题
经验分享·笔记·计算机网络·其他·1024程序员节
earthzhang20219 天前
《深入浅出HTTPS》读书笔记(20):口令和PEB算法
开发语言·网络协议·算法·https·1024程序员节
一个通信老学姐10 天前
专业140+总分410+浙江大学842信号系统与数字电路考研经验浙大电子信息与通信工程,真题,大纲,参考书。
考研·信息与通信·信号处理·1024程序员节