微信小程序 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 颗星。

相关推荐
随心............1 小时前
python基础综合案例(数据可视化-动态柱状图)
1024程序员节
洛可可白2 小时前
CentOS 7 上安装 MySQL 8.0 教程
linux·服务器·mysql·centos·1024程序员节
爱学习的执念2 小时前
外包干了7天,技术明显退步。。。。。
1024程序员节
程序员阿鹏2 小时前
详解:模板设计模式
java·开发语言·jvm·后端·设计模式·eclipse·1024程序员节
计算机学姐5 小时前
基于协同过滤算法的旅游网站推荐系统
vue.js·mysql·算法·mybatis·springboot·旅游·1024程序员节
会发光的猪。6 小时前
uniapp+华为HBuilder X 4.29跑鸿蒙模拟器报错没有签名授权
javascript·vue.js·华为·uni-app·bug·harmonyos·1024程序员节
小段闯天涯6 小时前
vscode 插件推荐安装
vscode·1024程序员节
ProMer_Wang6 小时前
C#探索之路基础夯实篇(6):C#在Unity中的自定义特性
unity·c#·1024程序员节
V+zmm101347 小时前
警务辅助人员管理系统小程序ssm+论文源码调试讲解
java·小程序·毕业设计·mvc·课程设计·1024程序员节