当前位置: 首页 > news >正文

小程序 setData 学问多

为什么不能频繁 setData

先科普下 setData 做的事情:

在数据传输时,逻辑层会执行一次 JSON.stringify 来去除掉 setData 数据中不可传输的部分,之后将数据发送给视图层。同时,逻辑层还会将 setData 所设置的数据字段与 data 合并,使开发者可以用 this.data 读取到变更后的数据。

因此频繁调用,视图会一直更新,阻塞用户交互,引发性能问题。

但频繁调用是常见开发场景,能不能频繁调用的同时,视图延迟更新呢?

参考 Vue,我们能知道,Vue 每次赋值操作并不会直接更新视图,而是缓存到一个数据更新队列中,异步更新,再触发渲染,此时多次赋值,也只会渲染一次。

于是有网友就给出了这套方案的实现方法:

let newState = null
const asyncSetData = ({
    vm,
    newData,
}) => {
    newState = {
        ...newState,
        ...newData,
    }
    Promise.resolve().then(() => {
        if (!newState) return
        vm.setData({
            ...newState,
        })
        newState = null
    })
}

由于异步代码会在同步代码之后执行,因此,当你多次使用 asyncSetData 设置 newState 时,newState 都会被缓存起来,并异步 setData 一次

但同时,这个方案也会带来一个新的问题,同步代码会阻塞页面的渲染

同步代码会阻塞页面的渲染的问题其实在浏览器中也存在,但在小程序中,由于是逻辑、视图双线程架构,因此逻辑并不会阻塞视图渲染,这是小程序的优点,但在这套方案将会丢失这个优点。

鱼与熊掌不可兼得也!

对于信息流页面,数据过多怎么办

单次设置的数据不能超过 1024kB,请尽量避免一次设置过多的数据

通常,我们拉取到分页的数据 newList,添加到数组里,一般是这么写:

this.setData({
    list: this.data.list.concat(newList)
})

随着分页次数的增加,list 会逐渐增大,当超过 1024 kb 时,程序会报 exceed max data size 错误。

为了避免这个问题,我们可以直接修改 list 的某项数据,而不是对整个 list 重新赋值:

let length = this.data.list.length;
let newData = newList.reduce((acc, v, i)=>{
  acc[`list[${length+i}]`] = v;
  return acc;
}, {});
this.setData(newData);

这看着似乎还有点繁琐,为了简化操作,我们可以把 list 的数据结构从一维数组改为二维数组:list = [newList, newList], 每次分页,可以直接将整个 newList 赋值到 list 作为一个子数组,此时赋值方式为:

let length = this.data.list.length;
this.setData({
    [`list[${length}]`]: newList
});

同时,模板也需要相应改成二重循环:

<block wx:for="{{list}}" wx:for-item="{{listItem}}" wx:key="{{listItem}}">
  <child wx:for="{{listItem}}" wx:key="{{item}}"></child>
</block>

下拉加载,让我们一夜回到解放前

信息流产品,总避免不了要做下拉加载。

下拉加载的数据,需要插到 list 的最前面,所以我们应该这样做:

this.setData({
  'list[-1]': newList
})

哦不,对不起,上面是错的,应该是下面这样:

this.setData({
  list: this.data.list.unshift(newList)
});

这下好,又是一次性修改整个数组,一夜回到解放前......

为了解决这个问题,这里需要一点奇淫巧技:

  • 为下拉加载维护一个单独的二维数组 pullDownList
  • 在渲染时,用 wxs 将 pullDownList reverse 一下

此时,当下拉加载时,便可以只修改数组的某个子项:

let length = this.data.pullDownList.length;
this.setData({
    [`pullDownList[${length}]`]: newList
});

关键在于渲染时候的反向渲染

<wxs module="utils">
function reverseArr(arr) {
  console.log
  return arr.reverse()
}
module.exports = {
  reverseArr: reverseArr
}
</wxs>
<block wx:for="{{utils.reverseArr(pullDownList)}}" wx:for-item="{{listItem}}" wx:key="{{listItem}}">
  <child wx:for="{{listItem}}" wx:key="{{item}}"></child>
</block>

<block wx:for="{{list}}" wx:for-item="{{listItem}}" wx:key="{{listItem}}">
  <child wx:for="{{listItem}}" wx:key="{{item}}"></child>
</block>

问题解决!

参考资料

  • 终极蛇皮上帝视角之微信小程序之告别 setData, 佯真愚, 2018年08月12日

相关文章:

  • 洛谷P5163 WD与地图
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 轻松防止服务器被黑
  • spring cloud构建互联网分布式微服务云平台-服务网关zuul
  • 了解语音交互:从“若琪,今天杭州的天气”发生了什么?
  • 阿里云SLB出现502 Bad Gateway 错误排查解决方法
  • bat(DOS)常用命令详解
  • 力扣(LeetCode)357
  • 来,膜拜下android roadmap,强大的执行力
  • JS · \r\n被转义导致出错
  • [译] 每天一段 Spring 5 官方文档(5.1.4.RELEASE)—— Spring Framework Overview 10
  • P3398 仓鼠找sugar (一道LCA的裸题)
  • 创建一个 Django 项目
  • GitHub如何下载clone指定的tag
  • 技术面试感觉什么都会,面试官一问回答不上来怎么办?
  • SegmentFault for Android 3.0 发布
  • 【知识碎片】第三方登录弹窗效果
  • Apache的80端口被占用以及访问时报错403
  • Brief introduction of how to 'Call, Apply and Bind'
  • codis proxy处理流程
  • conda常用的命令
  • es6(二):字符串的扩展
  • iOS 系统授权开发
  • java小心机(3)| 浅析finalize()
  • JS函数式编程 数组部分风格 ES6版
  • JS实现简单的MVC模式开发小游戏
  • leetcode46 Permutation 排列组合
  • leetcode98. Validate Binary Search Tree
  • Mithril.js 入门介绍
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • Octave 入门
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • vue2.0项目引入element-ui
  • vue数据传递--我有特殊的实现技巧
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 两列自适应布局方案整理
  • 如何优雅地使用 Sublime Text
  • 深入浏览器事件循环的本质
  • 详解移动APP与web APP的区别
  • 应用生命周期终极 DevOps 工具包
  • 赢得Docker挑战最佳实践
  • raise 与 raise ... from 的区别
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​虚拟化系列介绍(十)
  • # 数据结构
  • #includecmath
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (33)STM32——485实验笔记
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (Note)C++中的继承方式
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (办公)springboot配置aop处理请求.
  • (独孤九剑)--文件系统
  • (附源码)springboot宠物医疗服务网站 毕业设计688413