小程序09 小程序中的数据

对小程序中的数据相关知识的学习笔记。

小程序中数据的作用域

逻辑层负责产生、处理程序,小程序的JS脚本运行在同一个JSCore线程中

逻辑层和渲染层是一对多关系,但页面对象(Page)和页面层级(Webview)一一对应。

(1)全局数据

1
2
3
4
5
6
7
8
// app.js
App({
globalData: 'I am global data' // 全局共享数据
})

// 其他页面脚本other.js
var appInstance = getApp()
console.log(appInstance.globalData) // 输出: I am global data

App实例是单例的,因此在App中定义的数据可以在不同页面共享

(2)页面共享数据

1
2
3
4
5
6
7
8
console.log('加载 page.js')
var count = 0
Page({
onLoad: function() {
count += 1
console.log('第 ' + count + ' 次启动这个页面')
}
})

Page构造器外面定义的变量,会一直保存在内存中,不会随着页面销毁而销毁。因此上面的count值会递增

这是因为页面所在的JS文件、app.js以及其他被require的JS文件,在小程序启动时会自动执行且被基础库注册,所以这些文件仅会被执行一次。之后页面都是通过Page构造器来创建Page实例来渲染的。

所以一般require的依赖或者第三方库JS以及getApp()都会放在页面共享数据中,避免重复加载。

(3)Page实例中的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
Page({
data: { text: "我用来改变界面显示" },
onLoad: function(options) {},
onReady: function() {},
onShow: function() {},
onHide: function() {},
onUnload: function() {},
text: "我不显示在页面上",
myData: {
a: '我也不显示在页面上',
b: true
}
})

定义在Page构造函数中的数据,随着每次页面创建、销毁,这些数据也会被创建、销毁,不会被保留在内存当中。这些数据的生命周期与页面的生命周期是相同的。

定义在data中的数据用来渲染页面,就像在Vue中定义在data属性中的数据是一样的,只不过在Vue中是直接通过this.text取值,在小程序中需要通过this.data.text取值

与界面渲染无关的数据不要放在data中,可以提高性能表现。

合理操作数据,提升性能

(1)数据通信

视图层在接收到初始数据data时进行初始渲染,在使用setData更新数据时,视图层进行重新渲染。当用户出发事件,视图层会将信息反馈给逻辑层。

这一切都是逻辑层与视图层两个线程通信的结果。数据量小于64kb时总时长可以控制在30ms以内。传输数据过大将导致这一事件增长。因此减少数据传输量是降低数据传输时间的有效方式。

(2)提升性能的准则

调用setData进行重渲染后,视图层会进行一个节点树Diff的过程,合并数据,用新节点数替换旧节点数,用于下次渲染。

setData发送数据不会进行Diff,而是全量发送,生成新的节点树在进行Diff、合并。

所以:

  1. 不要过于频繁调用setData,考虑将多次合并为一次
  2. 每次setData只改动的最小的单位数据
  3. 与界面渲染无关的数据不要设置的data
  4. 事件绑定时需要传输targetcurrentTargetdateset,所以不要再节点的data属性中放置过大的数据
  5. 精简优化WXML结构,降低JS代码复杂性,必要时使用分包优化

注意:

  • 如果不使用setData而是直接对this.data中的数据赋值,不仅不会改变页面状态,还会导致数据不一致(和React中是一样的,不用多说了)。
  • 不要将data中的属性值设为undefined,会导致一些莫名其妙的bug

组件中的通信

(1)业务组件,也业务数据紧密耦合

  • 全局变量获取参数,通过更改全局变量与外界通信
  • 通过props获取参数,通过triggerEvent与外界通讯

(2)纯组件,与业务数据无关

  • 只能通过props获取参数,通过triggerEvent与外界通讯

缓存数据

这里的缓存数据是小程序存储在设备硬盘的数据,类似WebStorage。小程序宿主环境从不同小程序和不同用户两个维度来隔离缓存空间。每个小程序的缓存空间上线为10MB

(1)缓存充当全局数据

  • 通过wx.getStorage/wx.getStorageSync读取本地缓存
  • 通过wx.setStorage/wx.setStorageSync写入本地缓存

(2)利用缓存提前渲染截面

在拉取数据(比如商品列表)后缓存在本地,在onLoad发起请求前,先检查本地是否有缓存,如果有缓存的话使用缓存渲染界面。然后等待wx.request请求成功后在success回调中再次重新渲染页面,并且更新缓存。

一般对数据实时性和一致性要求不高的页面可以利用这个方法做提前渲染,可以提供类似PWA的体验。

状态管理Westore

很多基于小程序的框架,类似mpVue,主打的是其他技术栈编译转小程序,并且可以编译为在H5等其他端运行的代码。

但是据统计,开发小程序使用最多的技术栈就是小程序本身的开发工具和语法,因为小程序本身的组件化、调试、发布、回滚、灰度、上报、统计、监控都是很优秀的。

但是小程序现在本身的状态管理可能是一个需要解决的痛点,官方还没有推出类似Redux、Vuex的解决方案。所以组件间叫复杂的数据共享、通讯以及跨页面的组件通讯,还是很容易让小程序难以维护和调试。

Westore是一款腾讯微信小程序解决方案,覆盖状态管理、跨页通讯、插件开发和云数据库开发。其技术方案:

有需要时可以尝试引入。

参考