網頁性能優化是前端一個老生常談的話題,但微信小程序由於雙線程的架構設計,跟傳統 Web
頁面不太同樣。因此,今天來探究下微信小程序內的性能優化問題。html
首先,要問你們一個問題:從打開微信小程序到首頁展現在你們面前,要通過哪些過程?(能夠類比與前端另外一個常見問題:Web
頁面從輸入 url
到頁面展現具體通過了哪些過程)前端
相信你們對 Web
頁面的展示過程很是清楚。那麼小程序呢,簡要地說,小程序要歷經下面幾個啓動過程:算法
小程序初始化: 微信初始化小程序環境:包括 Js
引擎和 WebView
進行初始化,並注入公共基礎庫。 這步是微信作的,在用戶打開小程序以前就已經準備好了,是小程序運行環境預加載。小程序
下載小程序代碼包 對小程序業務代碼包進行下載:下載的不是小程序的源代碼,而是編譯、壓縮、打包以後的代碼。微信小程序
加載小程序代碼包 對下載完成對代碼包進行注入執行。 此時,app.js
、頁面所在的 Js
文件和全部其餘被 require
的 Js
文件會被自動執行一次,小程序基礎庫會完成全部頁面的註冊。瀏覽器
初始化小程序首頁 拉取數據,從邏輯層傳遞到視圖層,進行渲染。緩存
既然清楚了小程序的啓動過程,那咱們就能夠針對其中的每個環節進行性能分析和優化。性能優化
因爲這個環節是微信執行的,屬於小程序底層的執行耗時,因此咱們開發者沒法操控。已知的是:iOS
初始化比 Android
快一些。bash
通常來講:下載環節是耗時比較長的環節。 對低於 1MB
的代碼包,其下載時間能夠控制在 929ms(iOS)、1500ms(Android)內。 那麼提高下載性能最關鍵的一點是:控制包的大小。微信
常見的控制代碼包大小的方法以下:
若是小程序比較複雜,優化後的代碼總量仍然較大,此時能夠採用分包加載的方式進行優化。
其原理是: 通常狀況下,小程序的代碼將打包在一塊兒,在小程序啓動時一次性下載完成。 採用分包時,小程序的代碼包能夠被劃分爲幾個:一個是「主包」,包含小程序啓動時會立刻打開的頁面代碼和相關資源;其他是「分包」,包含其他的代碼和資源。 這樣,小程序啓動時,只須要先將主包下載完成,就能夠馬上啓動小程序。這樣就能夠顯著下降小程序代碼包的下載時間。
可是這個時候又出現了另外一個問題,在咱們訪問分包頁面時,須要先下載完分包代碼,才能打開分包頁面,這是能感受到到明顯卡頓,體驗也是比較差的。
咱們能夠經過配置 preloadRule
進行分包預加載:打開首頁,加載完主包後,靜默加載其餘分包。
除了普通分包方案,小程序還有獨立分包的方案。 獨立分包是小程序中一種特殊類型的分包,能夠獨立於主包和其餘分包運行。從獨立分包中頁面進入小程序時,不須要下載主包。當用戶進入普通分包或主包內頁面時,主包纔會被下載。 咱們能夠把它用於一些比較獨立的頁面,好比活動頁等。
到了首屏渲染這個環節,有如下的幾個優化建議:
提早請求:在頁面 onLoad
階段就能夠發起異步請求,不用等頁面 ready
。若是能在前置頁面點擊跳轉時預請求當前頁的核心異步請求,效果會更好;
善用緩存:對一些變更頻率很低的異步數據進行緩存,下次啓動時能夠直接利用;
優化交互:在首屏渲染的期間,利用 loading
效果或展現骨架圖,來緩解用戶等待的焦慮。
其實,頁面初始化的時間大體由頁面初始數據通訊時間和初始渲染時間兩部分構成。其中,數據通訊的時間指數據從邏輯層開始組織數據到視圖層徹底接收完畢的時間,數據量小於 64KB
時總時長能夠控制在30ms內。傳輸時間與數據量大致上呈現正相關關係,傳輸過大的數據將使這一時間顯著增長。於是減小傳輸數據量是下降數據傳輸時間的有效方式。
初始渲染完畢後,視圖層能夠在開發者調用setData後執行界面更新。
與傳統的瀏覽器 Web
頁面最大區別在於,小程序的是基於 雙線程 模型: 在這種架構中,視圖層使用 WebView
做爲渲染載體,而邏輯層是由獨立的 JavascriptCore
做爲運行環境。
二者都是獨立的模塊,並不具有數據直接共享的通道。視圖層和邏輯層的數據傳輸,要由 Native 的 JSBrigde
作中轉。
小程序經過 setData
更新數據到視圖改變,完整的流程以下:
setData
方法;JSON.stringify
來去除掉 setData
數據中不可傳輸的部分,將待傳輸數據轉換成字符串並拼接到特定的JS腳本, 並經過 evaluateJavascript
執行腳本將數據傳輸到渲染層。WebView JS
線程會對腳本進行編譯,獲得待更新數據後進入渲染隊列等待 WebView
線程空閒時進行頁面渲染。WebView
線程開始執行渲染時,將 data
和 setData
數據套用在WXML
片斷上,獲得一個新節點樹。通過新虛擬節點樹與當前節點樹的 diff
對比,將差別部分更新到UI視圖。最後,將 setData
數據合併到 data
中,並用新節點樹替換舊節點樹,用於下一次重渲染。如上文所說:一次 setData
帶來兩次開銷:通訊的開銷 + WebView
更新的開銷。 setData
是小程序開發使用最頻繁的 API
之一,也是最容易引起性能問題的。
因此使用時須要注意如下幾點:
與界面渲染無關的數據最好不要設置在 data
中,能夠考慮設置在 page
對象的其餘字段下;
this.setData({
a: '與渲染有關的字符串',
b: '與渲染無關的字符串'
})
// 能夠優化爲
this.setData({
a: '與渲染有關的字符串',
})
this.b = '與渲染無關的字符串'
複製代碼
不要過於頻繁調用 setData
,應考慮將屢次 setData
合併成一次 setData
調用;
this.setData({ a: 1 })
this.setData({ b: 2 })
// 可優化爲
this.setData({ a: 1, b: 2 })
複製代碼
當須要在頻繁觸發的用戶事件(如 PageScroll 、 Resize 事件)中調用 setData ,合理的利用函數防抖(debounce) 和 函數節流(throttle) 。
還能夠本身設計一個 diff
算法,從新對 setData 進行封裝,使得在 setData
執行以前,讓待更新的數據與原 data
數據作 diff
對比,若是同樣則跳過執行更新。很多小程序框架都有其相似的封裝。
列表局部更新 在更新列表的某一個數據時。不要用 setData
進行所有數據的刷新。查找對應 id
的那條數據的下標(index
是不會改變的),用 setData
進行局部刷新。
this.setData({
`list[${index}]` = newList[index]
})
複製代碼
合理使用小程序組件 自定義組件的更新只在組件內部進行,不會影響頁面其餘元素。由於各個組件具備獨立的邏輯空間、數據、樣式環境及 setData
調用。 基於自定義組件的 Shadow DOM
模型設計,咱們能夠將頁面中一些須要高頻執行 setData
更新的功能模塊(如倒計時、進度條等)封裝成自定義組件嵌入到頁面中。 當這些自定義組件視圖須要更新時,執行的是組件本身的 setData
,新舊節點樹的對比計算和渲染樹的更新都只限於組件內有限的節點數量,有效下降渲染時間開銷。
固然,並非使用自定義組件越多會越好,頁面每新增一個自定義組件, Exparser
須要多管理一個組件實例,內存消耗會更大。所以要合理的使用自定義組件,同時頁面設計也要注意不濫用標籤。
其實性能優化最重要的是拿數聽說話。可是如今小程序裏沒有完整成熟的定量的性能評測標準,目前有如下的分析工具可供參考:
性能 Trace 工具 微信 Andoid 6.5.10
開始,提供了 Trace
導出工具,開發者能夠在開發者工具 Trace Panel
中使用該功能。 使用教程: developers.weixin.qq.com/miniprogram…
性能面板 從微信 6.5.8
開始,提供了性能面板讓開發者瞭解小程序的性能。開發者能夠在開發版小程序下打開性能面板。 打開方法:進入開發版小程序,進入右上角更多按鈕,點擊 顯示性能窗口
加載性能監控 在小程序後臺,咱們能夠看到加載性能監控。指標有三個:
啓動總耗時
下載耗時
初次渲染耗時
總啓動耗時 = 下載耗時 + 初次渲染耗時 + 其餘耗時。
優化後可根據以上幾個工具進行數據對比,來判斷優化的效果。
主要參考來源: