【微信小程序】性能優化

內容整理於微信公開課javascript

爲何要作性能優化?

一切性能優化都是爲了體驗優化html

1. 使用小程序時,是否會常常遇到以下問題?

  • 打開是一直白屏java

  • 打開是loading態,轉好幾圈web

  • 個人頁面點了怎麼跳轉這麼慢?小程序

  • 個人列表怎麼越滑越卡?微信小程序

2. 咱們優化的方向有哪些?

  • 啓動加載性能緩存

  • 渲染性能性能優化

3. 啓動加載性能

1. 首次加載

你是否見太小程序首次加載時是這樣的圖?bash

小程序加載

這張圖中的三種狀態對應的都是什麼呢?微信

小程序啓動時,微信會爲小程序展現一個固定的啓動界面,界面內包含小程序的圖標、名稱和加載提示圖標。此時,微信會在背後完成幾項工做:下載小程序代碼包加載小程序代碼包初始化小程序首頁。下載到的小程序代碼包不是小程序的源代碼,而是編譯、壓縮、打包以後的代碼包。

2. 加載順序

小程序加載的順序是如何?

微信會在小程序啓動前爲小程序準備好通用的運行環境。這個運行環境包括幾個供小程序使用的線程,並在其中完成小程序基礎庫的初始化,預先執行通用邏輯,儘量作好小程序的啓動準備。這樣能夠顯著減小小程序的啓動時間。

小程序運行
經過2,咱們知道了,問題1中第一張圖是 資源準備(代碼包下載);第二張圖是 業務代碼的注入以及落地頁首次渲染;第三張圖是 落地頁數據請求時的loading態(部分小程序存在)

3. 控制包大小

提高體驗最直接的方法是控制小程序包的大小,這是最顯而易見的

  • 勾選開發者工具中「上傳代碼時,壓縮代碼」選項;

  • 及時清理無用的代碼和資源文件(包括無用的日誌代碼)

  • 減小資源包中的圖片等資源的數量和大小(理論上除了小icon,其餘圖片資源從網絡下載),圖片資源壓縮率有限

從開發者的角度看,控制代碼包大小有助於減小小程序的啓動時間。對低於1MB的代碼包,其下載時間能夠控制在929ms(iOS)、1500ms(Android)內

4. 採用分包加載機制

根據業務場景,將用戶訪問率高的頁面放在主包裏,將訪問率低的頁面放入子包裏,按需加載;

分包加載
使用分包時須要注意代碼和資源文件目錄的劃分。啓動時須要訪問的頁面及其依賴的資源文件應放在主包中。

5 採用分包預加載技術

在4的基礎上,當用戶點擊到子包的目錄時,仍是有一個代碼包下載的過程,這會感受到明顯的卡頓,因此子包也不建議拆的太大,固然咱們能夠採用子包預加載技術,並不須要等到用戶點擊到子包頁面後在下載子包,而是能夠根據後期數據,作子包預加載,將用戶在當先頁可能點擊的子包頁面先加載,當用戶點擊後直接跳轉;

分包預加載
這種基於配置的子包預加載技術,是能夠根據用戶網絡類型來判斷的,當用戶處於網絡條件好時才預加載;是靈活可控的

6. 採用獨立分包技術

目前不少小程序主包+子包(2M+6M)的方式,可是在作不少運營活動時,咱們會發現活動(紅包)是在子包裏,可是運營、產品投放的落地頁連接是子包連接,這是的用戶在直達落地時,必須先下載主包內容(通常比較大),在下載子包內容(相對主包,較小),這使得在用戶停留時間比較短的小程序場景中,用戶體驗不是很好,並且浪費了很大部分流量;

獨立分包
能夠採用獨立分包技術,區別於子包,和主包之間是無關的,在功能比較獨立的子包裏,使用戶只需下載分包資源;

7. 首屏加載的優化建議

7.1 提早請求

異步請求能夠在頁面onLoad就加載,不須要等頁面ready後在異步請求數據;固然,若是能在前置頁面點擊跳轉時預請求當前頁的核心異步請求,效果會更好;

7.2 利用緩存

利用storage API, 對變更頻率比較低的異步數據進行緩存,二次啓動時,先利用緩存數據進行初始化渲染,而後後臺進行異步數據的更新,這不只優化了性能,在無網環境下,用戶也能很順暢的使用到關鍵服務;

7.3 避免白屏

能夠在前置頁面將一些有用的字段帶到當前頁,進行首次渲染(列表頁的某些數據--> 詳情頁),沒有數據的模塊能夠進行骨架屏的佔位,使用戶不會等待的很焦慮,甚至走了;

7.4 及時反饋

及時的對須要用戶等待的交互操做進行反饋,避免用戶覺得小程序卡了,無響應


渲染性能優化

1. 小程序渲染原理

雙線程下的界面渲染,小程序的邏輯層和渲染層是分開的兩個線程。在渲染層,宿主環境會把WXML轉化成對應的JS對象,在邏輯層發生數據變動的時候,咱們須要經過宿主環境提供的setData方法把數據從邏輯層傳遞到渲染層,再通過對比先後差別,把差別應用在原來的Dom樹上,渲染出正確的UI界面。

分析這個流程不可貴知:頁面初始化的時間大體由頁面初始數據通訊時間和初始渲染時間兩部分構成。其中,數據通訊的時間指數據從邏輯層開始組織數據到視圖層徹底接收完畢的時間, 數據量小於64KB時總時長能夠控制在30ms內。傳輸時間與數據量大致上呈現正相關關係,傳輸過大的數據將使這一時間顯著增長。於是減小傳輸數據量是下降數據傳輸時間的有效方式。

2. 避免使用不當setData

在數據傳輸時,邏輯層會執行一次JSON.stringify來去除掉setData數據中不可傳輸的部分,以後將數據發送給視圖層。同時,邏輯層還會將setData所設置的數據字段與data合併,使開發者能夠用this.data讀取到變動後的數據。所以,爲了提高數據更新的性能,開發者在執行setData調用時,最好遵循如下原則:

2.1 不要過於頻繁調用setData,應考慮將屢次setData合併成一次setData調用;

2.2 數據通訊的性能與數據量正相關,於是若是有一些數據字段不在界面中展現且數據結構比較複雜或包含長字符串,則不該使用setData來設置這些數據;

2.3 與界面渲染無關的數據最好不要設置在data中,能夠考慮設置在page對象的其餘字段下

提高數據更新性能方式的代碼示例

Page({
  onShow: function() {

    // 不要頻繁調用setData
    this.setData({ a: 1 })
    this.setData({ b: 2 })
    // 絕大多數時候可優化爲
    this.setData({ a: 1, b: 2 })

    // 不要設置不在界面渲染時使用的數據,並將界面無關的數據放在data外
    this.setData({
      myData: {
        a: '這個字符串在WXML中用到了',
        b: '這個字符串未在WXML中用到,並且它很長…………………………'
      }
    })
    // 能夠優化爲
    this.setData({
      'myData.a': '這個字符串在WXML中用到了'
    })
    this._myData = {
      b: '這個字符串未在WXML中用到,並且它很長…………………………'
    }

  }
})
複製代碼
  • 利用setData進行列表局部刷新

在一個列表中,有n條數據,採用上拉加載更多的方式,假如這個時候想對其中某一個數據進行點贊操做,還能及時看到點讚的效果

  • 解決方法

一、能夠採用setData全局刷新,點贊完成以後,從新獲取數據,再次進行全局從新渲染,這樣作的優勢是:方便,快捷!缺點是:用戶體驗極其很差,當用戶刷量100多條數據後,從新渲染量大會出現空白期(沒有渲染過來)

二、說到重點了,就是利用setData局部刷新

> a.將點讚的`id`傳過去,知道點的是那一條數據, 將點讚的`id`傳過去,知道點的是那一條數據
複製代碼
<view wx:if="{{!item.status}}" class="btn" data-id="{{index}}" bindtap="couponTap">當即領取</view>
複製代碼
> b.從新獲取數據,查找相對應id的那條數據的下標(`index`是不會改變的)
> c.用setData進行局部刷新
複製代碼
this.setData({
    list[index] = newList[index]
})
複製代碼

其實這個小操做對剛剛接觸到微信小程序的人來講應該是不容易發現的,不理解setData還有這樣的寫法。

2.4 切勿在後臺頁面進行setData

在一些頁面會進行一些操做,而到頁面跳轉後,代碼邏輯還在執行,此時多個webview是共享一個js進程;後臺的setData操做會搶佔前臺頁面的渲染資源;

3. 用戶事件使用不當

視圖層將事件反饋給邏輯層時,一樣須要一個通訊過程,通訊的方向是從視圖層到邏輯層。由於這個通訊過程是異步的,會產生必定的延遲,延遲時間一樣與傳輸的數據量正相關,數據量小於64KB時在30ms內。下降延遲時間的方法主要有兩個。

1.去掉沒必要要的事件綁定(WXML中的bindcatch),從而減小通訊的數據量和次數; 2.事件綁定時須要傳輸targetcurrentTargetdataset,於是不要在節點的data前綴屬性中放置過大的數據。

4. 視圖層渲染原理

4.1首次渲染

初始渲染髮生在頁面剛剛建立時。初始渲染時,將初始數據套用在對應的WXML片斷上生成節點樹。節點樹也就是在開發者工具WXML面板中看到的頁面樹結構,它包含頁面內全部組件節點的名稱、屬性值和事件回調函數等信息。最後根據節點樹包含的各個節點,在界面上依次建立出各個組件。

在這整個流程中,時間開銷大致上與節點樹中節點的總量成正比例關係。於是減小WXML中節點的數量能夠有效下降初始渲染和重渲染的時間開銷,提高渲染性能。

簡化WXML代碼的例子

<view data-my-data="{{myData}}"> <!-- 這個 view 和下一行的 view 能夠合併 -->
  <view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
    <text> <!-- 這個 text 一般是不必的 -->
      {{myText}}
    </text>
  </view>
</view>

<!-- 能夠簡化爲 -->

<view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
  {{myText}}
</view>
複製代碼

4.2 重渲染

初始渲染完畢後,視圖層能夠屢次應用setData的數據。每次應用setData數據時,都會執行重渲染來更新界面。初始渲染中獲得的data和當前節點樹會保留下來用於重渲染。每次重渲染時,將datasetData數據套用在WXML片斷上,獲得一個新節點樹。而後將新節點樹與當前節點樹進行比較,這樣能夠獲得哪些節點的哪些屬性須要更新、哪些節點須要添加或移除。最後,將setData數據合併到data中,並用新節點樹替換舊節點樹,用於下一次重渲染。

在進行當前節點樹與新節點樹的比較時,會着重比較setData數據影響到的節點屬性。於是,去掉沒必要要設置的數據、減小setData的數據量也有助於提高這一個步驟的性能。

5. 使用自定義組件

自定義組件的更新只在組件內部進行,不受頁面其餘不能份內容的影響;好比一些運營活動的定時模塊能夠單獨抽出來,作成一個定時組件,定時組件的更新並不會影響頁面上其餘元素的更新;各個組件也將具備各自獨立的邏輯空間。每一個組件都分別擁有本身的獨立的數據、setData調用。

6. 避免不當的使用onPageScroll

每一次事件監聽都是一次視圖到邏輯的通訊過程,因此只在必要的時候監聽pageSrcoll

總結

小程序啓動加載性能

  • 控制代碼包的大小

  • 分包加載

  • 首屏體驗(預請求,利用緩存,避免白屏,及時反饋

小程序渲染性能

  • 避免不當的使用setData

  • 合理利用事件通訊

  • 避免不當的使用onPageScroll

  • 優化視圖節點

  • 使用自定義組件

相關文章
相關標籤/搜索