摘要:傳輸時(shí)間與數(shù)據(jù)量大體上呈現(xiàn)正相關(guān)關(guān)系,傳輸過(guò)大的數(shù)據(jù)將使這一時(shí)間顯著增加。小程序不管從組件化開(kāi)發(fā)調(diào)試發(fā)布灰度回滾上報(bào)統(tǒng)計(jì)監(jiān)控和最近的云能力都非常完善,小程序的工程化簡(jiǎn)直就是前端的典范。
研究背景
上一篇文章了解了小程序的生命周期,接下來(lái)研究一下數(shù)據(jù)通信,我覺(jué)得清楚了生命周期和數(shù)據(jù)通信,就能對(duì)整個(gè)程序有一定的把控能力,定位問(wèn)題和解決問(wèn)題的能力將大幅提高天生的延時(shí)
我剛開(kāi)始擼小程序的時(shí)候,覺(jué)得看看文檔就可以了,導(dǎo)致寫(xiě)了很多垃圾代碼坑人坑己,相信大部分初學(xué)者也不會(huì)去仔細(xì)研究文檔,更別說(shuō)啰里啰嗦的指南了,在通讀小程序官方指南后,我覺(jué)得很有必要為初學(xué)者總結(jié)一番,教學(xué)相長(zhǎng)
為了解決管控與安全問(wèn)題,小程序提供了一個(gè)沙箱環(huán)境來(lái)運(yùn)行開(kāi)發(fā)者的JavaScript 代碼
基于雙線(xiàn)程模型,意味著任何數(shù)據(jù)傳遞都是線(xiàn)程間的通信
在小程序架構(gòu)里,這一切都會(huì)變成異步
異步會(huì)使得各部分的運(yùn)行時(shí)序變得復(fù)雜一些,因此邏輯層與渲染層需要有一定的機(jī)制保證時(shí)序正確
這些工作在小程序框架里會(huì)處理好,開(kāi)發(fā)者只需要理解生命周期,以及控制合適的時(shí)機(jī)更新UI即可
上一篇文章我們學(xué)習(xí)了小程序的生命周期,本文主要理解如何控制合適的時(shí)機(jī)更新UI
如何控制合適的時(shí)機(jī)更新UI小程序作為MVVM框架中的一員,數(shù)據(jù)驅(qū)動(dòng)是核心,得數(shù)據(jù)者得天下
要理解數(shù)據(jù)通信,和生命周期、運(yùn)行機(jī)制密不可分,像雙線(xiàn)程通信模型、數(shù)據(jù)驅(qū)動(dòng)、底層框架、界面渲染機(jī)制等等,本文不會(huì)展開(kāi)敘述,也不可能講的比官方文檔更好、更實(shí)時(shí)
本文主要理解以下幾點(diǎn):(想了半天,才概括如下)
1、小程序中數(shù)據(jù)的作用域
2、合理操作數(shù)據(jù),提升性能
3、組件間的數(shù)據(jù)通信
4、緩存數(shù)據(jù)
5、擴(kuò)展-狀態(tài)管理westore
在這之前,還是上幾張官方的圖,有個(gè)概念便于后續(xù)理解
明確幾點(diǎn)概念
渲染層和數(shù)據(jù)相關(guān)
邏輯層負(fù)責(zé)產(chǎn)生、處理數(shù)據(jù),小程序的JS腳本運(yùn)行在同一個(gè)JsCore線(xiàn)程里
邏輯層和渲染層是一對(duì)多的關(guān)系,但頁(yè)面對(duì)象(page)和頁(yè)面層級(jí)(webview)一一對(duì)應(yīng)
一、小程序中數(shù)據(jù)的作用域 1、全局?jǐn)?shù)據(jù)// app.js App({ globalData: "I am global data" // 全局共享數(shù)據(jù) }) // 其他頁(yè)面腳本other.js var appInstance = getApp() console.log(appInstance.globalData) // 輸出: I am global data
App實(shí)例是單例的,因此不同頁(yè)面直接可以通過(guò)App實(shí)例下的屬性來(lái)共享數(shù)據(jù)
2、頁(yè)面共享數(shù)據(jù)簡(jiǎn)單來(lái)說(shuō)就是頁(yè)面所在的JS中Page構(gòu)造器外定義的變量
執(zhí)行如下示例代碼以驗(yàn)證
console.log("加載 page.js") var count = 0 Page({ onLoad: function() { count += 1 console.log("第 " + count + " 次啟動(dòng)這個(gè)頁(yè)面") } })
你會(huì)發(fā)現(xiàn)小程序啟動(dòng)時(shí),打印了"加載 page.js",每次打開(kāi)這個(gè)頁(yè)面,count變量會(huì)遞增,不會(huì)隨著頁(yè)面的銷(xiāo)毀而銷(xiāo)毀
由于頁(yè)面所在的JS文件、app.js和所有其他被require的JS文件,在小程序啟動(dòng)時(shí)自動(dòng)執(zhí)行并被基礎(chǔ)庫(kù)注冊(cè),所以邏輯層(看作所有js的集合)只執(zhí)行一次,之后都是通過(guò)Page構(gòu)造器創(chuàng)建Page實(shí)例來(lái)渲染頁(yè)面
一般require的依賴(lài)或者第三方庫(kù)JS以及getApp(),我們都會(huì)放在頁(yè)面共享的數(shù)據(jù)中
3、Page實(shí)例中的數(shù)據(jù)也就是每個(gè)Page構(gòu)造器中的數(shù)據(jù),沒(méi)錯(cuò)!這就是我們每天搬磚的地方
Page({ data: { text: "我用來(lái)改變界面顯示" }, onLoad: function(options) { }, onReady: function() { }, onShow: function() { }, onHide: function() { }, onUnload: function() { }, text: "我不顯示在頁(yè)面上", myData:{ a: "我也不顯示在頁(yè)面上", b: true } })
大家應(yīng)該都知道data中的數(shù)據(jù)用來(lái)渲染頁(yè)面,和VUE一樣,不過(guò)VUE中只要寫(xiě)this.text,而小程序中要寫(xiě)this.data.text,每次寫(xiě)到這個(gè)就郁悶,其實(shí)與界面渲染無(wú)關(guān)的數(shù)據(jù)最好不要設(shè)置在data中,對(duì)性能也是大有好處
4、自定義組件中的數(shù)據(jù)properties外部傳值
data內(nèi)部數(shù)據(jù)
emmmmmm自定義組件有必要另開(kāi)一篇總結(jié)
二、合理操作數(shù)據(jù),提升性能 數(shù)據(jù)通信頁(yè)面初始數(shù)據(jù)通信:視圖層在接收到初始數(shù)據(jù)data時(shí),進(jìn)行初始渲染
更新數(shù)據(jù)通信:視圖層在接收到更新數(shù)據(jù)setData時(shí),進(jìn)行重渲染
用戶(hù)事件通信:一個(gè)用戶(hù)事件被觸發(fā),視圖層會(huì)將信息反饋給邏輯層
一切都是2個(gè)線(xiàn)程通信的結(jié)果,數(shù)據(jù)量小于64KB時(shí)總時(shí)長(zhǎng)可以控制在30ms內(nèi)。傳輸時(shí)間與數(shù)據(jù)量大體上呈現(xiàn)正相關(guān)關(guān)系,傳輸過(guò)大的數(shù)據(jù)將使這一時(shí)間顯著增加。因而減少傳輸數(shù)據(jù)量是降低數(shù)據(jù)傳輸時(shí)間的有效方式
提升性能須遵循的原則調(diào)用setData執(zhí)行重渲染時(shí),視圖層將data和setData數(shù)據(jù)套用在WXML片段上,得到一個(gè)新節(jié)點(diǎn)樹(shù),然后與當(dāng)前節(jié)點(diǎn)樹(shù)進(jìn)行比較,這樣可以得到哪些節(jié)點(diǎn)的哪些屬性需要更新、哪些節(jié)點(diǎn)需要添加或移除,最后,將setData數(shù)據(jù)合并到data中,并用新節(jié)點(diǎn)樹(shù)替換舊節(jié)點(diǎn)樹(shù),用于下一次重渲染。
可以看出邏輯層setData發(fā)送數(shù)據(jù)給更新視圖時(shí),需要兩個(gè)線(xiàn)程的一些通信消耗,且不會(huì)diff數(shù)據(jù),只會(huì)一股腦傳過(guò)去,生成新節(jié)點(diǎn)樹(shù),每一次通信都需要經(jīng)過(guò)傳輸、生成、比較、合并
為了提升數(shù)據(jù)更新的性能,最好遵循以下原則:
1、不要過(guò)于頻繁調(diào)用setData,應(yīng)考慮將多次setData合并成一次setData調(diào)用
2、數(shù)據(jù)通信的性能與數(shù)據(jù)量正相關(guān),每次只設(shè)置需要改變的最小單位數(shù)據(jù)
3、與界面渲染無(wú)關(guān)的數(shù)據(jù)最好不要設(shè)置在data中,可以考慮設(shè)置在page對(duì)象的其他字段下
其他優(yōu)化策略:
1、去掉不必要的事件綁定(WXML中的bind和catch),從而減少通信的數(shù)據(jù)量和次數(shù)
2、事件綁定時(shí)需要傳輸target和currentTarget的dataset,因而不要在節(jié)點(diǎn)的data前綴屬性中放置過(guò)大的數(shù)據(jù)
3、精簡(jiǎn)代碼,降低WXML結(jié)構(gòu)和JS代碼的復(fù)雜性,必要時(shí)使用分包優(yōu)化
注意:
直接修改 Page實(shí)例的this.data 而不調(diào)用 this.setData 是無(wú)法改變頁(yè)面的狀態(tài)的,還會(huì)造成數(shù)據(jù)不一致
不要把data中的任意一項(xiàng)的value設(shè)為undefined,否則可能會(huì)有引起一些不可預(yù)料的bug
三、組件間的數(shù)據(jù)通信 組件區(qū)分業(yè)務(wù)組件和純組件業(yè)務(wù)組件與業(yè)務(wù)數(shù)據(jù)緊耦合,換一個(gè)項(xiàng)目可能該組件就用不上,除非非常類(lèi)似的項(xiàng)目
業(yè)務(wù)組件和頁(yè)面一樣通過(guò) 全局變量 獲得所需參數(shù),通過(guò)更改 全局變量 與外界通訊
業(yè)務(wù)組件也可以通過(guò) props 獲得所需參數(shù),通過(guò) triggerEvent 與外界通訊
純組件與業(yè)務(wù)數(shù)據(jù)無(wú)關(guān),可移植和復(fù)用
純組件只能通過(guò) props 獲得所需參數(shù),通過(guò) triggerEvent 與外界通訊
四、緩存數(shù)據(jù)本地?cái)?shù)據(jù)緩存是小程序存儲(chǔ)在當(dāng)前設(shè)備上硬盤(pán)上的數(shù)據(jù),小程序宿主環(huán)境從不同小程序和不同用戶(hù)兩個(gè)維度來(lái)隔離緩存空間,每個(gè)小程序的緩存空間上限為10MB
緩存充當(dāng)全局?jǐn)?shù)據(jù)
通過(guò)wx.getStorage/wx.getStorageSync讀取本地緩存
通過(guò)wx.setStorage/wx.setStorageSync寫(xiě)數(shù)據(jù)到緩存
利用本地緩存提前渲染界面
我們?cè)诶∩唐妨斜砗蟀蚜斜泶嬖诒镜鼐彺胬?/p>
在onLoad發(fā)起請(qǐng)求前,先檢查是否有緩存過(guò)列表
如果有的話(huà)直接渲染界面
等到wx.request的success回調(diào)之后再覆蓋本地緩存重新渲染新的列表
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) // 覆蓋緩存數(shù)據(jù) } } }) } })
一般在對(duì)數(shù)據(jù)實(shí)時(shí)性/一致性要求不高的頁(yè)面采用這個(gè)方法來(lái)做提前渲染,用以?xún)?yōu)化小程序體驗(yàn)
五、擴(kuò)展-狀態(tài)管理westore引用
眾所周知,小程序通過(guò)頁(yè)面或組件各自的 setData 再加上各種父子、祖孫、姐弟、姑姑與堂兄等等組件間的通訊會(huì)把程序搞成一團(tuán)漿糊,如果再加上跨頁(yè)面之間的組件通訊,會(huì)讓程序非常難維護(hù)和調(diào)試。雖然市面上出現(xiàn)了許多技術(shù)棧編譯轉(zhuǎn)小程序的技術(shù),但是我覺(jué)沒(méi)有戳中小程序的痛點(diǎn)。小程序不管從組件化、開(kāi)發(fā)、調(diào)試、發(fā)布、灰度、回滾、上報(bào)、統(tǒng)計(jì)、監(jiān)控和最近的云能力都非常完善,小程序的工程化簡(jiǎn)直就是前端的典范。而開(kāi)發(fā)者工具也在持續(xù)更新,可以想象的未來(lái),組件布局的話(huà)未必需要寫(xiě)代碼了。而且據(jù)統(tǒng)計(jì),開(kāi)發(fā)小程序使用最多的技術(shù)棧是使用小程序本身的開(kāi)發(fā)工具和語(yǔ)法,所以最大的痛點(diǎn)只剩下?tīng)顟B(tài)管理和跨頁(yè)通訊
現(xiàn)在主流的MVVM框架如vue/react/angluar都有狀態(tài)管理,小程序也可以有,由于小程序的即時(shí)特性,迭代更新非???,所以對(duì)于小程序我是崇尚原生開(kāi)發(fā)的,不過(guò)多端合一也是很nice的解決方案,自己玩的時(shí)候當(dāng)然要試試dcloud公司的uniapp
廢話(huà)不多說(shuō),直接貼圖和鏈接,有興趣的自行研究哈,Westore 的方案:
Westore項(xiàng)目地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101390.html
摘要:運(yùn)行機(jī)制小程序啟動(dòng)會(huì)有兩種情況,一種是冷啟動(dòng),一種是熱啟動(dòng)。建議小程序在必要時(shí)使用監(jiān)聽(tīng)內(nèi)存告警事件,進(jìn)行必要的內(nèi)存清理。 前言 以小程序?yàn)榍腥朦c(diǎn),深入理解總結(jié)方方面面的知識(shí)點(diǎn),做成系列文章,希望能得到大神的指點(diǎn)和幫助新人入門(mén),承上啟下才是好程序猿由于是系列第一篇文章,緊跟著的是一大段廢話(huà),只關(guān)心技術(shù)的可以跳過(guò) 轉(zhuǎn)眼半年又要過(guò)去了,意味著來(lái)新公司快半年了,離上次寫(xiě)文章也半年了,渾渾噩噩...
摘要:大多數(shù)待遇豐厚的開(kāi)發(fā)職位都要求開(kāi)發(fā)者精通多線(xiàn)程技術(shù)并且有豐富的程序開(kāi)發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線(xiàn)程相關(guān)的問(wèn)題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱(chēng)之為序列化,反之將字節(jié)流重建成對(duì)象稱(chēng)之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...
面試舊敵之紅黑樹(shù)(直白介紹深入理解) - Android - 掘金 讀完本文你將了解到: 什么是紅黑樹(shù) 黑色高度 紅黑樹(shù)的 5 個(gè)特性 紅黑樹(shù)的左旋右旋 指定節(jié)點(diǎn) x 的左旋 右圖轉(zhuǎn)成左圖 指定節(jié)點(diǎn) y 的右旋左圖轉(zhuǎn)成右圖 紅黑樹(shù)的平衡插入 二叉查找樹(shù)的插入 插入后調(diào)整紅黑樹(shù)結(jié)構(gòu) 調(diào)整思想 插入染紅后... java 多線(xiàn)程同步以及線(xiàn)程間通信詳解 & 消費(fèi)者生產(chǎn)者模式 & 死鎖 & Thread...
閱讀 1878·2023-04-26 02:46
閱讀 2013·2021-11-25 09:43
閱讀 1153·2021-09-29 09:35
閱讀 2108·2019-08-30 15:56
閱讀 3432·2019-08-30 15:54
閱讀 2645·2019-08-29 16:35
閱讀 3130·2019-08-29 15:25
閱讀 3302·2019-08-29 14:01