小程序 ---- (setData关于赋值对象属性的问题)

一、什么是setData?

小程序的官方setData方法其实分为两个步骤:一是改变对应的 this.data的值;二是在步骤一的同时将数据从逻辑层发送到视图层。

我们先来了解一下小程序页面的一些底层关系:

小程序的globalData是响应式的么_图层


小程序中各个页面是相互独立的,一个页面分为渲染层(视图层webview)、逻辑层(JavaScript)和系统层(底层)。

在架构上,视图层webview和逻辑层JavaScript是相互独立的,并不具备数据直接共享的通道。 换而言之,如果要将逻辑层中的data数据渲染到页面中,他们之间是无法直接通信的,往往需要系统层作为中间角色,而这个系统底层的方法,就是setData。

原理:当我们想操作数据,将数据渲染到视图层的时候,必须经过系统层。当系统层收到这个数据的同时,做了两件事:一是将数据传递给了逻辑层(通过JavaScriptCore);这个过程是同步的。 二是系统层把数据转发给视图层,然后视图层将数据渲染出来。这个过程是异步的
视图层和逻辑层的数据传输,实际上是通过两个层级的JavaScriptCore所实现。即用户传输的数据,需要将其转换为字符串的形式(JSON.stringify)传递。同时把转换后的数据内容拼接成一份JS脚本,再通过执行JS脚本的形式传递到两个层级的独立环境之中。

而,我们一般操作小程序里面的数据有两种方法:

  • this.setData({})
  • this.data.params

现在我们回过头来看开头的那两个步骤,我们可以理解为两个通道。在我们使用setData操作数据的时候,系统底层接收到数据之后,通道一用来同步逻辑层的数据;通道二用来发送数据给视图层。
需要注意的是,this.data.params这种设置数据的方法是同步的,而将数据从逻辑层发送到视图层这个步骤是异步的。所以如果直接修改 this.data.params 而不调用 this.setData方法,是无法改变页面的数据的,只会改变逻辑层(JavaScript)的数据,还会造成数据不一致。

接下来说说setData操作对象数据时候的一些坑。

二、错误的赋值

先在data里面定义好一个对象:

params: {
  name: '张三',
  age: '18',
  gender: 1
}

接下来我们修改一下张三的年龄,操作数据:

this.setData({
  params: {
  	age: 20
  }
})

结果:除了年龄以外的数据全部被抹去,这种方式相当于是将params重新赋值,显然不可取。

//  params: {
//   age: 20
// }

三、正确的赋值

正确的操作年龄数据如下:

this.setData({
  ['params.age']: 20
})

结果:指定对象的某一个属性进行赋值,才不会影响到其他属性。

// params: {
//   name: '张三',
//   age: 20,
//   gender: 1
// }

四、注意事项

基本上,除了操作对象的属性的时候,需要注意一下,操作其他数据类型则没有太多明显的坑。有的都已经罗列在下面了:

  1. 仅支持设置可JSON化的数据,如果不是 JSON 对象数据格式,需要将数据进行转化成json对象`,key:value形式;
  2. 不要把 data中任何一项的value设为undefined,否则这一项将不被设置并可能遗留一些潜在问题;
  3. 页面中需要显示的数据,可以挂载在data下面初始化,虽然这个值不一定要先设置,但是建议先声明然后在使用;
  4. 避免在同一时间内对setData的调用过于频繁(setData接口的调用涉及逻辑层与渲染层间的线程通信,通信过于频繁可能导致处理队列阻塞,界面渲染不及时而导致卡顿,应避免无用的频繁调用),建议每秒调用setData的次数不超过 20 次;
  5. 单次设置的数据不能超过1024kB(1M),不要一次设置过多的数据(由于小程序运行逻辑线程与渲染线程之上,setData的调用会把数据从逻辑层传到渲染层,数据太大会增加通信时间,会增加脚本的编译执行时间,占用 WebView JS 线程),setData的数据在JSON.stringify后不超过 256K;
  6. 避免 setData 数据冗余(setData操作会引起框架处理一些渲染界面相关的工作,避免将未绑定在 WXML 的变量传入setData,减少不必要的性能消耗);
  7. 后台态页面进行setData(比如退出小程序),当页面进入后台态(用户不可见),不应该继续去进行 setData,后台态页面的渲染用户是无法感受到的,另外后台态页面去 setData 也会抢占前台页面的执行;