微信小程序 啟動性能

2020-07-31 13:41 更新

啟動性能

小程序啟動是小程序用戶體驗(yàn)中極為重要的一環(huán),啟動耗時(shí)過長會造成小程序用戶流失。

本章節(jié)的啟動只包括小程序冷啟動,不包括小程序后臺切前臺的熱啟動。

一、啟動流程

在進(jìn)行啟動優(yōu)化之前,先簡單介紹以下小程序的啟動過程。在小程序啟動過程中,主要包括以下幾個(gè)方面:

  • 注 1:小程序啟動的這些部分不是串行完成的,會盡可能的并行進(jìn)行。
  • 注 2:小程序啟動各部分不是每次啟動都完整進(jìn)行的,會盡可能的利用緩存。

1. 資源準(zhǔn)備

1.1 小程序相關(guān)信息準(zhǔn)備

在用戶訪問小程序時(shí),微信客戶端需要從微信后臺獲取小程序的配置、版本、權(quán)限等相關(guān)信息,以對小程序進(jìn)行必要的版本管理、權(quán)限控制和校驗(yàn)等。

對啟動耗時(shí)的影響

信息的獲取和更新會影響小程序的啟動耗時(shí),尤其體現(xiàn)在用戶首次訪問小程序時(shí)。

為了在盡量降低影響啟動耗時(shí)的情況下保證信息的實(shí)時(shí)性,這些信息會在本地緩存,并通過一定的機(jī)制定期進(jìn)行更新。

1.2 小程序運(yùn)行環(huán)境準(zhǔn)備

在執(zhí)行小程序代碼之前,微信客戶端需要準(zhǔn)備小程序運(yùn)行的基礎(chǔ)環(huán)境。

小程序的運(yùn)行環(huán)境包括小程序進(jìn)程、原生部分的 UI 元素(如 導(dǎo)航欄、tabBar等)、渲染頁面使用的 WebView 容器、運(yùn)行開發(fā)者 JS 代碼的 JS 引擎、小程序基礎(chǔ)庫等等。

對啟動耗時(shí)的影響

運(yùn)行環(huán)境的準(zhǔn)備耗時(shí)較長,對小程序的啟動耗時(shí)有明顯影響。

為了盡可能的降低運(yùn)行環(huán)境準(zhǔn)備對啟動耗時(shí)的影響,微信客戶端會根據(jù)用戶的使用場景和設(shè)備資源的使用情況,提前對運(yùn)行環(huán)境進(jìn)行部分地預(yù)加載。但由于受到設(shè)備資源和操作系統(tǒng)調(diào)度的影響,目前很難保證每次小程序啟動時(shí)都有預(yù)加載的環(huán)境。

1.3 小程序代碼包準(zhǔn)備

小程序啟動時(shí)需要從服務(wù)器獲取代碼包地址、下載小程序代碼包,并對代碼包進(jìn)行校驗(yàn)。根據(jù)小程序頁面所在分包和使用的插件不同,一次啟動可能需要下載多個(gè)代碼包或插件包。

當(dāng)小程序版本發(fā)生更新時(shí),微信客戶端還需要對代碼包進(jìn)行增量更新。

對啟動耗時(shí)的影響

下載耗時(shí)是啟動耗時(shí)中的重要瓶頸,與代碼包或增量包的體積正相關(guān)。微信采用 ZSTD 算法對小程序代碼包進(jìn)行壓縮,以盡可能降低下載過程中傳輸?shù)臄?shù)據(jù)量。

考慮到包大小對用戶體驗(yàn)的影響,平臺限制單個(gè)代碼包的大小上限為 2M。代碼包上限的增加對于開發(fā)者來說,能夠?qū)崿F(xiàn)更豐富的功能,但對于用戶來說,也增加了下載流量和本地空間的占用。為了保證啟動速度,開發(fā)者應(yīng)該盡可能的控制代碼包大小。

2. 開發(fā)者代碼注入(邏輯層)

小程序啟動時(shí)需要從代碼包內(nèi)讀取小程序的配置和代碼,并注入到 JS 引擎中。在主包代碼注入過程中,會觸發(fā)小程序的 App.onLaunch 和首次 App.onShow 生命周期。在開發(fā)者代碼注入完成后,框架側(cè)會根據(jù)用戶訪問的頁面進(jìn)行一些頁面數(shù)據(jù)初始化工作,觸發(fā)首頁的 Page.onLoad, Page.onShow 事件。

對啟動耗時(shí)的影響

開發(fā)者代碼的注入耗時(shí)直接影響小程序的啟動耗時(shí)。在主流的 JS 引擎中,代碼注入耗時(shí)包括編譯和執(zhí)行等環(huán)節(jié),代碼量、同步接口調(diào)用和一些復(fù)雜的計(jì)算,都會影響注入耗時(shí)。

由于首頁渲染需要使用邏輯層發(fā)送的數(shù)據(jù),如果開發(fā)者代碼注入耗時(shí)過長,也會延遲首頁渲染開始的時(shí)間。

在部分平臺上,微信客戶端會使用 V8 引擎的 Code Caching 技術(shù)對代碼編譯結(jié)果進(jìn)行緩存,降低二次注入時(shí)的編譯耗時(shí)。

3. 開發(fā)者代碼注入(渲染層)

開發(fā)者的 wxss 和 wxml 會經(jīng)過編譯注入到渲染層,包含頁面渲染需要的頁面結(jié)構(gòu)和樣式信息。渲染層的注入耗時(shí)主要和頁面結(jié)構(gòu)復(fù)雜度和使用的自定義組件數(shù)量有關(guān)。

渲染層和邏輯層的開發(fā)者代碼注入是并行進(jìn)行的。

對啟動耗時(shí)的影響

由于首頁渲染需要使用渲染層的頁面結(jié)構(gòu)和樣式信息,如果開發(fā)者代碼注入耗時(shí)過長,會延遲首頁渲染開始的時(shí)間。

4. 首頁(初次)渲染

在開發(fā)者代碼注入完成后,結(jié)合邏輯層得到的數(shù)據(jù)和渲染層得到的頁面結(jié)構(gòu)和樣式信息,小程序框架會進(jìn)行小程序首頁的渲染,展示小程序首屏,并觸發(fā)首頁的 Page.onReady 事件。Page.onReady 事件觸發(fā)標(biāo)志小程序啟動過程完成。

對啟動耗時(shí)的影響

首頁渲染耗時(shí)主要受頁面結(jié)構(gòu)和參與渲染的數(shù)據(jù)量影響。

二、關(guān)鍵概念

在討論小程序啟動耗時(shí)時(shí),需要明確幾個(gè)概念:

1. 小程序首屏渲染完成

從開發(fā)者角度看,小程序首屏渲染完成的標(biāo)志是首頁 Page.onReady 事件觸發(fā)。

從框架的角度來說,小程序的首屏的內(nèi)容是基于小程序的初始數(shù)據(jù),以及在渲染開始前到達(dá)的 setData 數(shù)據(jù)渲染的。

首屏渲染完成不表示小程序頁面一定有完整內(nèi)容,開發(fā)者觸發(fā)的 setData(例如通過 wx.request 異步請求數(shù)據(jù))不一定能參與到首屏渲染中。

由于框架和啟動流程的差異,小程序定義的首屏渲染完成不等同于瀏覽器的 load 事件。

2. 小程序啟動階段

從用戶點(diǎn)擊訪問小程序到小程序首屏渲染完成(首頁 Page.onReady 事件觸發(fā))。

3. 打開率/到達(dá)率

小程序首屏渲染完成 PV 與 用戶點(diǎn)擊訪問小程序 PV 的比值。流失率 = 1 - 打開率

三、啟動性能優(yōu)化

在啟動流程中,小程序代碼包準(zhǔn)備、開發(fā)者代碼注入和首頁渲染是與開發(fā)者相關(guān)的,開發(fā)者可以進(jìn)行一定的優(yōu)化工作。其他部分目前開發(fā)者暫時(shí)無法干預(yù),框架側(cè)負(fù)責(zé)進(jìn)行持續(xù)的優(yōu)化。

1. 小程序代碼包優(yōu)化

代碼包優(yōu)化的核心手段是降低代碼包大小,代碼包大小直接影響了下載耗時(shí),影響用戶啟動小程序時(shí)的體驗(yàn)。

開發(fā)者可以采取以下手段優(yōu)化代碼包大小:

1.1 分包加載

使用 分包加載 是優(yōu)化小程序啟動耗時(shí)效果最明顯的手段。建議開發(fā)者按照功能劃分,將小程序的功能按使用頻率和場景拆分成分包,實(shí)現(xiàn)代碼包的按需加載。

分包加載具有以下優(yōu)勢:

  • 承載更多功能:小程序單個(gè)代碼包的體積上限為 2M,使用分包可以提升小程序代碼包總體積上限,承載更多的功能與服務(wù)。
  • 降低代碼包下載耗時(shí):使用分包后可以顯著啟動時(shí)需要下載的代碼包大小,在不影響功能正常使用的前提下明顯提升啟動耗時(shí)。
  • 降低開發(fā)者代碼注入耗時(shí):小程序啟動時(shí)會一次性注入全部的開發(fā)者代碼,使用分包后可以降低注入的代碼量,從而降低注入耗時(shí)。
  • 降低頁面渲染耗時(shí)

此外,結(jié)合分包加載的幾個(gè)擴(kuò)展功能,可以進(jìn)一步優(yōu)化啟動耗時(shí):

分包預(yù)下載

在使用「分包加載」后,雖然能夠顯著提升小程序的啟動速度,但是當(dāng)用戶在使用小程序過程中跳轉(zhuǎn)到分包內(nèi)頁面時(shí),需要等待分包下載完成后才能進(jìn)入頁面,造成頁面切換的延遲,影響小程序的使用體驗(yàn)。分包預(yù)下載便是為了解決首次進(jìn)入分包頁面時(shí)的延遲問題而設(shè)計(jì)的。

獨(dú)立分包

但小程序中的某些場景(如廣告頁、活動頁、支付頁等),通常功能不是很復(fù)雜且相對獨(dú)立,對啟動性能有很高的要求。獨(dú)立分包可以獨(dú)立于主包和其他分包運(yùn)行。從獨(dú)立分包中頁面進(jìn)入小程序時(shí),不需要下載主包。建議開發(fā)者將部分對啟動性能要求很高的頁面放到特殊的獨(dú)立分包中。

獨(dú)立分包和分包預(yù)下載可以配合使用,獲得更好的效果,詳情請參考獨(dú)立分包與分包預(yù)下載教程

1.2 代碼重構(gòu)和優(yōu)化

通過代碼重構(gòu),降低代碼冗余。在使用如 Webpack 等打包工具時(shí),要盡量利用 tree-shaking 等特性去除冗余代碼,也要注意防止打包時(shí)引入不需要的庫和依賴。

1.3 控制代碼包內(nèi)圖片等資源

避免在代碼包中包含或在 WXSS 中使用 base64 內(nèi)聯(lián)過多、過大的圖片,應(yīng)盡量采用網(wǎng)絡(luò)圖片。代碼包內(nèi)的圖片一般應(yīng)只包含一些體積較小的圖標(biāo)。聲音、視頻等其他類型的資源應(yīng)盡量避免放到代碼包中。

小程序代碼包在下載時(shí)會使用 ZSTD 算法進(jìn)行壓縮,降低下載時(shí)傳輸?shù)臄?shù)據(jù)量。這些資源文件會占用大量代碼包體積,并且通常難以進(jìn)一步被壓縮,對于下載耗時(shí)的影響比代碼文件大得多。

1.4 及時(shí)清理沒有使用到的代碼和資源

在日常開發(fā)的時(shí)候,我們可能引入了一些新的庫文件,而過了一段時(shí)間后,由于各種原因又不再使用這個(gè)庫了,我們常常會只是去掉了代碼里的引用,而忘記刪掉這類庫文件了。

目前小程序打包是會將工程下所有文件都打入代碼包內(nèi),也就是說,這些沒有被實(shí)際使用到的庫文件和資源也會被打入到代碼包里,從而影響到整體代碼包的大小。

2. 開發(fā)者代碼注入優(yōu)化

開發(fā)者代碼注入的優(yōu)化可以從優(yōu)化執(zhí)行耗時(shí)和優(yōu)化代碼量兩部分著手。

2.1 減少啟動過程的同步調(diào)用

在小程序啟動流程中,會注入開發(fā)者代碼并順序同步執(zhí)行 App.onLaunch, App.onShow, Page.onLoad, Page.onShow。在小程序初始化代碼(Page,App 定義之外的內(nèi)容)和啟動相關(guān)的幾個(gè)生命周期中,應(yīng)避免執(zhí)行復(fù)雜的計(jì)算邏輯或過度使用Sync結(jié)尾的同步API,如 wx.getStorageSync,wx.getSystemInfoSync 等。對于 getSystemInfo, getSystemInfoSync 的結(jié)果應(yīng)進(jìn)行緩存,避免重復(fù)調(diào)用。

2.2 使用懶注入

通常情況下,在小程序啟動時(shí),啟動頁面所在分包和主包(獨(dú)立分包除外)的所有JS代碼會全部合并注入,包括其他未訪問的頁面以及未用到自定義組件,造成很多沒有使用的代碼注入到小程序運(yùn)行環(huán)境中,影響注入耗時(shí)和內(nèi)存占用。

自基礎(chǔ)庫版本 2.11.1 起,小程序支持僅注入當(dāng)前頁面需要的自定義組件和當(dāng)前頁面代碼,以降低小程序的啟動時(shí)間和運(yùn)行時(shí)內(nèi)存。開發(fā)者可以在 app.json 中配置:

{
  "lazyCodeLoading": "requiredComponents"
}

注意:添加這項(xiàng)配置后,未使用到的代碼文件將不被執(zhí)行。

3. 頁面渲染優(yōu)化

3.1 提前首屏數(shù)據(jù)請求

大部分小程序在渲染首頁時(shí),需要依賴服務(wù)端的接口數(shù)據(jù),小程序?yàn)殚_發(fā)者提供了提前發(fā)起數(shù)據(jù)請求的能力:

  • 數(shù)據(jù)預(yù)拉取:能夠在小程序冷啟動的時(shí)候通過微信后臺提前向第三方服務(wù)器拉取業(yè)務(wù)數(shù)據(jù),當(dāng)代碼包加載完時(shí)可以更快地渲染頁面,減少用戶等待時(shí)間,從而提升小程序的打開速度。
  • 周期性更新:在用戶未打開小程序的情況下,也能從服務(wù)器提前拉取數(shù)據(jù),當(dāng)用戶打開小程序時(shí)可以更快地渲染頁面,減少用戶等待時(shí)間。

3.2 骨架屏

在頁面數(shù)據(jù)未準(zhǔn)備好時(shí)(如需要通過網(wǎng)絡(luò)獲?。?,盡量避免展示空白頁面,應(yīng)先通過骨架屏展示頁面的大致結(jié)構(gòu),請求數(shù)據(jù)返回后在進(jìn)行頁面更新。以提升用戶的等待意愿。

3.3 緩存請求數(shù)據(jù)

小程序提供了wx.setStorage、wx.getStorage等讀寫本地緩存的能力,數(shù)據(jù)存儲在本地,返回的會比網(wǎng)絡(luò)請求快。如果開發(fā)者基于某些原因無法采用數(shù)據(jù)預(yù)拉取與周期性更新,我們推薦優(yōu)先從緩存中獲取數(shù)據(jù)來渲染視圖,等待網(wǎng)絡(luò)請求返回后進(jìn)行更新。

3.4 精簡首屏數(shù)據(jù)

我們推薦開發(fā)者延遲請求非關(guān)鍵渲染數(shù)據(jù),與視圖層渲染無關(guān)的數(shù)據(jù)盡量不要放在 data 中,加快頁面渲染完成時(shí)間。

四、啟動性能分析

1. 性能數(shù)據(jù)獲取

1.1 小程序助手「性能分析」板塊

小程序管理后臺的性能數(shù)據(jù)還沒有更新,正在規(guī)劃改版中,建議在改版完成前開發(fā)者以小程序助手的性能數(shù)據(jù)為準(zhǔn)。

建議開發(fā)者使用小程序助手中「性能分析」板塊,持續(xù)關(guān)注小程序性能。性能分析從 啟動性能、運(yùn)行性能和網(wǎng)絡(luò)性能 三個(gè)維度提供性能數(shù)據(jù),供開發(fā)者根據(jù)平臺、機(jī)型、網(wǎng)絡(luò)環(huán)境和訪問來源等條件做精細(xì)化分析。掃描下方小程序碼即可立即體驗(yàn)。

目前,小程序助手中只包括微信客戶端 >= 7.0.3 版本的正式版小程序數(shù)據(jù)。

1.2 通過 API 在小程序內(nèi)獲取

開發(fā)者可以在小程序中根據(jù)自身業(yè)務(wù)需有進(jìn)行性能打點(diǎn),也可以使用 wx.getPerformance ,獲取當(dāng)前小程序性能相關(guān)的信息。

在獲取信息后,開發(fā)者可以自行上報(bào)或使用 wx.reportPerformance 進(jìn)行測速。

1.3 體驗(yàn)評分

小程序工具中提供了體驗(yàn)評分工具,方便開發(fā)者能夠及時(shí)發(fā)現(xiàn)小程序的體驗(yàn)問題。

2. 影響啟動性能的因素

根據(jù)「啟動流程」一節(jié)介紹的啟動流程來看,影響小程序啟動耗時(shí)的因素眾多,分析小程序啟動性能是一個(gè)比較復(fù)雜的過程。

對于同一個(gè)小程序,以下因素會直接影響平均啟動耗時(shí):

  • 平臺: 不同平臺下(安卓、iOS、PC等)設(shè)備性能、操作系統(tǒng)、框架實(shí)現(xiàn)、優(yōu)化方案存在較大差異,啟動耗時(shí)也存在較大的差異。只有分平臺比較啟動耗時(shí)(包括各階段的耗時(shí))才有意義。
  • 下載比例:代碼包下載和更新都會顯著影響小程序啟動耗時(shí),在其他流程耗時(shí)穩(wěn)定的情況下,下載比例升高會影響大盤啟動耗時(shí)。
  • 入口頁面:不同頁面啟動時(shí),根據(jù)所在分包的不同,需要下載的代碼包數(shù)量和大小和代碼注入量都存在差異。不同頁面渲染耗時(shí)也存在差異。
  • 機(jī)型分布:啟動耗時(shí)和設(shè)備性能有較強(qiáng)關(guān)聯(lián),不同小程序或使用場景用戶群體的差異可能導(dǎo)致機(jī)型分布的差異,進(jìn)而影響大盤啟動耗時(shí)。
  • 網(wǎng)絡(luò)環(huán)境:網(wǎng)絡(luò)環(huán)境主要影響網(wǎng)絡(luò)請求的耗時(shí),如小程序信息獲取、代碼包下載等。

此外,下列情況也會間接影響啟動耗時(shí):

  • 場景/訪問來源:不同場景用戶訪問的頁面不同,訪問的目的性和自身的等待意愿也有差異,對啟動耗時(shí)和打開率都有一定影響。
  • 首次訪問用戶比例:用戶首次訪問小程序時(shí),需要完整的進(jìn)行小程序信息準(zhǔn)備、代碼包下載的流程、代碼緩存也需要重新生成,啟動耗時(shí)會比非首次訪問高。
  • 小程序版本更新:小程序版本更新時(shí),用戶需要更新小程序信息和代碼包,代碼緩存也需要重新生成,啟動耗時(shí)會出現(xiàn)上漲。

關(guān)于「性能分析」板塊數(shù)據(jù)

小程序助手中提供了啟動過程中和開發(fā)者相關(guān)的下載耗時(shí)、js注入耗時(shí)和初次渲染耗時(shí)供開發(fā)者優(yōu)化參考。

這里需要注意的是,啟動總耗時(shí) ≠ 下載耗時(shí) + js 注入耗時(shí) + 初次渲染耗時(shí)。在啟動過程中,下載不一定發(fā)生,也不一定只下載一個(gè)代碼包。js 注入耗時(shí)和渲染耗時(shí)也會受緩存更新而發(fā)生波動。

各階段耗時(shí)的下降不一定反應(yīng)在總耗時(shí)的下降。例如小程序新版本發(fā)布后,即使各階段耗時(shí)都下降,下載比例的升高反而可能導(dǎo)致總耗時(shí)的上升。

3. 影響打開率的因素

啟動性能用戶的等待意愿是影響打開率的兩個(gè)關(guān)鍵因素。在部分場景下,如果用戶等待意愿較低,即使啟動耗時(shí)很低,也不一定能獲得較高的打開率。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號