研究背景
上一篇文章了解了小程序的生命周期,接下来研究一下数据通讯,我以为清楚了生命周期和数据通讯,就能对整个程序有必定的把控能力,定位问题和解决问题的能力将大幅提升
我刚开始撸小程序的时候,以为看看文档就能够了,致使写了不少垃圾代码坑人坑己,相信大部分初学者也不会去仔细研究文档,更别说啰里啰嗦的指南了,在通读小程序官方指南后,我以为颇有必要为初学者总结一番,教学相长
天生的延时
- 为了解决管控与安全问题,小程序提供了一个沙箱环境来运行开发者的JavaScript 代码
- 基于双线程模型,意味着任何数据传递都是线程间的通讯
- 在小程序架构里,这一切都会变成异步
- 异步会使得各部分的运行时序变得复杂一些,所以逻辑层与渲染层须要有必定的机制保证时序正确
- 这些工做在小程序框架里会处理好,开发者只须要理解生命周期,以及控制合适的时机更新UI便可
- 上一篇文章咱们学习了小程序的生命周期,本文主要理解如何控制合适的时机更新UI
如何控制合适的时机更新UI
小程序做为MVVM框架中的一员,数据驱动是核心,得数据者得天下前端
- 要理解数据通讯,和生命周期、运行机制密不可分,像双线程通讯模型、数据驱动、底层框架、界面渲染机制等等,本文不会展开叙述,也不可能讲的比官方文档更好、更实时
- 本文主要理解如下几点:(想了半天,才归纳以下)
- 一、小程序中数据的做用域
- 二、合理操做数据,提高性能
- 三、组件间的数据通讯
- 四、缓存数据
- 五、扩展-状态管理westore
在这以前,仍是上几张官方的图,有个概念便于后续理解


明确几点概念vue
- 渲染层和数据相关
- 逻辑层负责产生、处理数据,小程序的JS脚本运行在同一个JsCore线程里
- 逻辑层和渲染层是一对多的关系,但页面对象(page)和页面层级(webview)一一对应
1、小程序中数据的做用域
一、全局数据
// app.js
App({
globalData: 'I am global data' // 全局共享数据
})
// 其余页面脚本other.js
var appInstance = getApp()
console.log(appInstance.globalData) // 输出: I am global data
- App实例是单例的,所以不一样页面直接能够经过App实例下的属性来共享数据
二、页面共享数据
- 简单来讲就是页面所在的JS中Page构造器外定义的变量
- 执行以下示例代码以验证
console.log('加载 page.js')
var count = 0
Page({
onLoad: function() {
count += 1
console.log('第 ' + count + ' 次启动这个页面')
}
})
- 你会发现小程序启动时,打印了'加载 page.js',每次打开这个页面,count变量会递增,不会随着页面的销毁而销毁
- 因为页面所在的JS文件、app.js和全部其余被require的JS文件,在小程序启动时自动执行并被基础库注册,因此逻辑层(看做全部js的集合)只执行一次,以后都是经过Page构造器建立Page实例来渲染页面
- 通常require的依赖或者第三方库JS以及getApp(),咱们都会放在页面共享的数据中
三、Page实例中的数据
- 也就是每一个Page构造器中的数据,没错!这就是咱们天天搬砖的地方
Page({
data: { text: "我用来改变界面显示" },
onLoad: function(options) { },
onReady: function() { },
onShow: function() { },
onHide: function() { },
onUnload: function() { },
text: "我不显示在页面上",
myData:{
a: '我也不显示在页面上',
b: true
}
})
- 你们应该都知道data中的数据用来渲染页面,和VUE同样,不过VUE中只要写this.text,而小程序中要写this.data.text,每次写到这个就郁闷,其实与界面渲染无关的数据最好不要设置在data中,对性能也是大有好处
四、自定义组件中的数据
- properties外部传值
- data内部数据
- emmmmmm自定义组件有必要另开一篇总结
2、合理操做数据,提高性能
数据通讯
- 页面初始数据通讯:视图层在接收到初始数据data时,进行初始渲染
- 更新数据通讯:视图层在接收到更新数据setData时,进行重渲染
- 用户事件通讯:一个用户事件被触发,视图层会将信息反馈给逻辑层
- 一切都是2个线程通讯的结果,数据量小于64KB时总时长能够控制在30ms内。传输时间与数据量大致上呈现正相关关系,传输过大的数据将使这一时间显著增长。于是减小传输数据量是下降数据传输时间的有效方式

提高性能须遵循的原则
调用setData执行重渲染时,视图层将data和setData数据套用在WXML片断上,获得一个新节点树,而后与当前节点树进行比较,这样能够获得哪些节点的哪些属性须要更新、哪些节点须要添加或移除,最后,将setData数据合并到data中,并用新节点树替换旧节点树,用于下一次重渲染。react

能够看出逻辑层setData发送数据给更新视图时,须要两个线程的一些通讯消耗,且不会diff数据,只会一股脑传过去,生成新节点树,每一次通讯都须要通过传输、生成、比较、合并git
为了提高数据更新的性能,最好遵循如下原则:github
- 一、不要过于频繁调用setData,应考虑将屡次setData合并成一次setData调用
- 二、数据通讯的性能与数据量正相关,每次只设置须要改变的最小单位数据
- 三、与界面渲染无关的数据最好不要设置在data中,能够考虑设置在page对象的其余字段下
其余优化策略:web
- 一、去掉没必要要的事件绑定(WXML中的bind和catch),从而减小通讯的数据量和次数
- 二、事件绑定时须要传输target和currentTarget的dataset,于是不要在节点的data前缀属性中放置过大的数据
- 三、精简代码,下降WXML结构和JS代码的复杂性,必要时使用分包优化
注意:小程序
- 直接修改 Page实例的this.data 而不调用 this.setData 是没法改变页面的状态的,还会形成数据不一致
- 不要把data中的任意一项的value设为undefined,不然可能会有引发一些不可预料的bug
3、组件间的数据通讯
组件区分业务组件和纯组件
- 业务组件与业务数据紧耦合,换一个项目可能该组件就用不上,除非很是相似的项目
- 业务组件和页面同样经过 全局变量 得到所需参数,经过更改 全局变量 与外界通信
- 业务组件也能够经过 props 得到所需参数,经过 triggerEvent 与外界通信
- 纯组件与业务数据无关,可移植和复用
- 纯组件只能经过 props 得到所需参数,经过 triggerEvent 与外界通信
4、缓存数据
本地数据缓存是小程序存储在当前设备上硬盘上的数据,小程序宿主环境从不一样小程序和不一样用户两个维度来隔离缓存空间,每一个小程序的缓存空间上限为10MBsegmentfault
缓存充当全局数据缓存
- 经过wx.getStorage/wx.getStorageSync读取本地缓存
- 经过wx.setStorage/wx.setStorageSync写数据到缓存
利用本地缓存提早渲染界面安全
- 咱们在拉取商品列表后把列表存在本地缓存里
- 在onLoad发起请求前,先检查是否有缓存过列表
- 若是有的话直接渲染界面
- 等到wx.request的success回调以后再覆盖本地缓存从新渲染新的列表
Page({
onLoad: function() {
var that = this
var list =wx.getStorageSync("list")
if (list) { // 本地若是有缓存列表,提早渲染
that.setData({
list: list
})
}
wx.request({
url: 'https://test.com/getproductlist',
success: function (res) {
if (res.statusCode === 200) {
list = res.data.list
that.setData({ // 再次渲染列表
list: list
})
wx.setStorageSync("list",list) // 覆盖缓存数据
}
}
})
}
})
- 通常在对数据实时性/一致性要求不高的页面采用这个方法来作提早渲染,用以优化小程序体验
5、扩展-状态管理westore
引用
众所周知,小程序经过页面或组件各自的 setData 再加上各类父子、祖孙、姐弟、姑姑与堂兄等等组件间的通信会把程序搞成一团浆糊,若是再加上跨页面之间的组件通信,会让程序很是难维护和调试。虽然市面上出现了许多技术栈编译转小程序的技术,可是我觉没有戳中小程序的痛点。小程序无论从组件化、开发、调试、发布、灰度、回滚、上报、统计、监控和最近的云能力都很是完善,小程序的工程化简直就是前端的典范。而开发者工具也在持续更新,能够想象的将来,组件布局的话未必须要写代码了。并且据统计,开发小程序使用最多的技术栈是使用小程序自己的开发工具和语法,因此最大的痛点只剩下状态管理和跨页通信
- 如今主流的MVVM框架如vue/react/angluar都有状态管理,小程序也能够有,因为小程序的即时特性,迭代更新很是快,因此对于小程序我是崇尚原生开发的,不过多端合一也是很nice的解决方案,本身玩的时候固然要试试dcloud公司的uniapp
- 废话很少说,直接贴图和连接,有兴趣的自行研究哈,Westore 的方案:

Westore项目地址