新聞中心
小編給大家分享一下微信小程序渲染性能調(diào)優(yōu)的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
成都創(chuàng)新互聯(lián)公司是一家專注于網(wǎng)站制作、成都網(wǎng)站建設與策劃設計,梨樹網(wǎng)站建設哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設十多年,網(wǎng)設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:梨樹等地區(qū)。梨樹做網(wǎng)站價格咨詢:18982081108
小程序的雙線程架構
與傳統(tǒng)的瀏覽器Web頁面最大區(qū)別在于,小程序的是基于 雙線程
模型的,在這種架構中,小程序的渲染層使用 WebView
作為渲染載體,而邏輯層則由獨立的 JsCore
線程運行 JS
腳本,雙方并不具備數(shù)據(jù)直接共享的通道,因此渲染層和邏輯層的通信要由 Native
的 JSBrigde
做中轉(zhuǎn)。
小程序更新視圖數(shù)據(jù)的通信流程
每當小程序視圖數(shù)據(jù)需要更新時,邏輯層會調(diào)用小程序宿主環(huán)境提供的 setData
方法將數(shù)據(jù)從邏輯層傳遞到視圖層,經(jīng)過一系列渲染步驟之后完成UI視圖更新。完整的通信流程如下:
小程序邏輯層調(diào)用宿主環(huán)境的 setData 方法。
邏輯層執(zhí)行 JSON.stringify 將待傳輸數(shù)據(jù)轉(zhuǎn)換成字符串并拼接到特定的JS腳本,并通過evaluateJavascript 執(zhí)行腳本將數(shù)據(jù)傳輸?shù)戒秩緦印?/p>
渲染層接收到后, WebView JS 線程會對腳本進行編譯,得到待更新數(shù)據(jù)后進入渲染隊列等待 WebView 線程空閑時進行頁面渲染。
WebView 線程開始執(zhí)行渲染時,待更新數(shù)據(jù)會合并到視圖層保留的原始 data 數(shù)據(jù),并將新數(shù)據(jù)套用在WXML片段中得到新的虛擬節(jié)點樹。經(jīng)過新虛擬節(jié)點樹與當前節(jié)點樹的 diff 對比,將差異部分更新到UI視圖。同時,將新的節(jié)點樹替換舊節(jié)點樹,用于下一次重渲染。
引發(fā)渲染性能問題的一些原因
在上述通信流程中,一些不恰當?shù)牟僮骺赡軙绊懙巾撁驿秩镜男阅埽?/p>
setData傳遞大量的新數(shù)據(jù)
數(shù)據(jù)的傳輸會經(jīng)歷跨線程傳輸和腳本編譯的過程,當數(shù)據(jù)量過大,會增加腳本編譯的執(zhí)行時間,占用 WebView JS
線程。
下圖是我們做的一組測試統(tǒng)計:在相同網(wǎng)絡環(huán)境下,各個機型分別對大小為 1KB
、 2KB
、 3KB
的數(shù)據(jù)執(zhí)行 setData
操作所消耗的時間。
從圖中可以看出, setData
數(shù)據(jù)傳輸量越大,數(shù)據(jù)傳輸所消耗的時間越大。
頻繁的執(zhí)行setData操作
頻繁的執(zhí)行 setData
會讓 WebView JS
線程一直忙碌于腳本的編譯、節(jié)點樹的對比計算和頁面渲染。導致的結(jié)果是:
頁面渲染結(jié)果有一定的延時。
用戶觸發(fā)頁面事件時,因 WebView JS 線程忙碌,用戶事件未能及時的傳輸?shù)竭壿媽佣鴮е路答佈舆t。
過多的頁面節(jié)點數(shù)
頁面初始渲染時,渲染樹的構建、計算節(jié)點幾何信息以及繪制節(jié)點到屏幕的時間開銷都跟頁面節(jié)點數(shù)量成正相關關系,頁面節(jié)點數(shù)量越多,渲染耗時越長。
每次執(zhí)行
setData
更新視圖,WebView JS
線程都要遍歷節(jié)點樹計算新舊節(jié)點數(shù)差異部分。當頁面節(jié)點數(shù)量越多,計算的時間開銷越大,減少節(jié)點樹節(jié)點數(shù)量可以有效降低重渲染的時間開銷。
渲染性能優(yōu)化
基于引發(fā)渲染性能問題的原因,我們可以制定一些優(yōu)化策略來避免性能問題的發(fā)生。
setData優(yōu)化
setData
作為邏輯層與視圖層通信的媒介,是最容易造成渲染性能瓶頸的 API
。我們在使用 setData
時應該遵循一些規(guī)則來盡可能避免性能問題的發(fā)生:
減少 setData
數(shù)據(jù)傳輸量
僅傳輸視圖層使用到的數(shù)據(jù),其他
JS
環(huán)境用到的數(shù)據(jù)存放到data
對象外。合理利用局部更新。
setData
是支持使用數(shù)據(jù)路徑
的方式對對象的局部字段進行更新,我們可能會遇到這樣的場景:list
列表是從后臺獲取的數(shù)據(jù),并展示在頁面上,當list
列表的第一項數(shù)據(jù)的src
字段需要更新時,一般情況下我們會從后臺獲取新的list
列表,執(zhí)行setData
更新整個list
列表。
// 后臺獲取列表數(shù)據(jù) const list = requestSync(); // 更新整個列表 this.setData({ list });
實際上,只有個別字段需要更新時,我們可以這么寫來避免整個 list
列表更新:
// 后臺獲取列表數(shù)據(jù) const list = requestSync(); // 局部更新列表 this.setData({ 'list[0].src': list[0].src });
降低 setData
執(zhí)行頻率
在不影響業(yè)務流程的前提下,將多個
setData
調(diào)用合并執(zhí)行,減少線程間通信頻次。當需要在頻繁觸發(fā)的用戶事件(如
PageScroll
、Resize
事件)中調(diào)用setData
,合理的利用函數(shù)防抖(debounce)
和函數(shù)節(jié)流(throttle)
可以減少setData
執(zhí)行次數(shù)。
函數(shù)防抖(debounce)
:函數(shù)在觸發(fā)n秒后才執(zhí)行一次,如果在n秒內(nèi)重復觸發(fā)函數(shù),則重新計算時間。
函數(shù)節(jié)流(throttle)
:單位時間內(nèi),只會觸發(fā)一次函數(shù),如果同一個單位時間內(nèi)觸發(fā)多次函數(shù),只會有一次生效。
除了讓開發(fā)者自覺遵循規(guī)則來減少 setData
數(shù)據(jù)傳輸量和執(zhí)行頻率之外,我們還可以自己設計一個 diff
算法,重新對 setData
進行封裝,使得在 setData
執(zhí)行之前,讓待更新的數(shù)據(jù)與原 data
數(shù)據(jù)做 diff
對比,計算出數(shù)據(jù)差異 patch
對象,判斷 patch
對象是否為空,如果為空則跳過執(zhí)行更新,否則再將 patch
對象執(zhí)行 setData
操作,從而達到減少數(shù)據(jù)傳輸量和降低執(zhí)行 setData
頻率的目的。
// setData重新封裝成新的方法,使得數(shù)據(jù)更新前先對新舊數(shù)據(jù)做diff對比,再執(zhí)行setData方法 this.update = (data) => { return new Promise((resolve, reject) => { const result = diff(data, this.data); if (!Object.keys(result).length) { resolve(null); return; } this.setData(result, () => { resolve(result); }); }); }
當然,可以直接引用這里 的現(xiàn)成 高性能小程序 setData
diff算法
具體流程如下圖:
善用自定義組件
小程序自定義組件的實現(xiàn)是由小程序官方設計的 Exparser
框架所支持,框架實現(xiàn)的自定義組件的組件模型與 Web Components
標準的 Shadow DOM
相似:
在頁面引用自定義組件后,當初始化頁面時, Exparser
會在創(chuàng)建頁面實例的同時,也會根據(jù)自定義組件的注冊信息進行組件實例化,然后根據(jù)組件自帶的 data
數(shù)據(jù)和組件WXML,構造出獨立的 Shadow Tree
,并追加到頁面 Composed Tree
。創(chuàng)建出來的 Shadow Tree
擁有著自己獨立的邏輯空間、數(shù)據(jù)、樣式環(huán)境及setData調(diào)用:
基于自定義組件的 Shadow DOM
模型設計,我們可以將頁面中一些需要高頻執(zhí)行 setData
更新的功能模塊(如倒計時、進度條等)封裝成自定義組件嵌入到頁面中。當這些自定義組件視圖需要更新時,執(zhí)行的是組件自己的 setData
,新舊節(jié)點樹的對比計算和渲染樹的更新都只限于組件內(nèi)有限的節(jié)點數(shù)量,有效降低渲染時間開銷。
下圖是我們在微保小程序WeDrive首頁中,將倒計時模塊抽取自定義組件前后的setData更新耗時對比:
從圖中可以看出,使用自定義組件后,倒計時模塊 setData
平均渲染耗時有了非常明顯的下降,實際在低端安卓機中體驗會感覺明顯的更流暢。
當然,并不是使用自定義組件越多會越好,頁面每新增一個自定義組件, Exparser
需要多管理一個組件實例,內(nèi)存消耗會更大,當內(nèi)存占用上升到一定程度,有可能導致 iOS
將部分 WKWebView
回收,安卓機體驗會變得更加卡頓。因此要合理的使用自定義組件,同時頁面設計也要注意不濫用標簽。
看完了這篇文章,相信你對“微信小程序渲染性能調(diào)優(yōu)的示例分析”有了一定的了解,如果想了解更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
本文名稱:微信小程序渲染性能調(diào)優(yōu)的示例分析
鏈接地址:http://fisionsoft.com.cn/article/jgegoj.html