研究背景
上一篇文章瞭解了小程序的生命週期,接下來研究一下數據通訊,我以爲清楚了生命週期和數據通訊,就能對整個程序有必定的把控能力,定位問題和解決問題的能力將大幅提升
我剛開始擼小程序的時候,以爲看看文檔就能夠了,致使寫了不少垃圾代碼坑人坑己,相信大部分初學者也不會去仔細研究文檔,更別說囉裏囉嗦的指南了,在通讀小程序官方指南後,我以爲頗有必要爲初學者總結一番,教學相長
天生的延時
- 爲了解決管控與安全問題,小程序提供了一個沙箱環境來運行開發者的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項目地址