QQ音樂 Android 客戶端的 Web 頁面日均 PV 達到千萬量級,然而頁面的開啟耗時與 Native 頁面相距甚遠,需要系統性優化。本文將介紹 QQ 音樂 Android 客戶端在進行 Web 頁面通用效能優化過程中的問題、思路、方案和效果,並嘗試對跨端場景的常見瓶頸和對策進行歸納。文章作者:關岳,QQ音樂客戶端開發工程師。
一、問題與目標
作為一款注重於內容運營的應用程式,QQ 音樂 Android 客戶端的 Web 頁面日均 PV 達到千萬量級,評論頁、MV 頁等核心頁面均有 Web 頁面參與,或完全由 Web 實現。
客戶端內 Web 頁面的開啟耗時與 Native 頁面相距甚遠,需要系統性優化。然而,現有的前端和跨端優化方案,存在一定侷限性。
1. 前端優化的侷限
針對 Web 頁面的耗時優化,在優化思路、方案、服務、工具鏈等方面都已經建設得非常詳細。然而,在客戶端內 Web 頁面這一場景,純前端優化存在以下兩個侷限:
-
無法規避 WebView 初始化耗時
-
受限於 WebView 生命週期範圍
從客戶端角度,除了思考優化 WebView 初始化耗時之外,還可以從 “擴充套件前端生命週期” 的角度出發,思考優化方案。
2. 跨端優化的侷限
現有跨端優化方案,包括離線包、VasSonic 等,為了達到最好的優化效果,均需要前端終端共同參與改造。這導致存量頁面的邏輯改造增加,對線上頁面不夠友好,引入額外的成本和風險。在前端開發資源不足時,這些優化的開展存在一定難度。
從減少前端開發工作量的角度來看,需要思考更具通用性、前端感知更小的優化方案。
3. 目標
基於本次優化的背景,本次優化提出以下兩方面的目標:增強通用性、減少前端改造成本。
二、指標設計
在展開優化思路和實施的同時,需要建立衡量優化效果的效能指標。
1. 客戶端現有效能指標資料
接下來基於客戶端內 Web 頁面載入過程,描述客戶端現有效能指標代表的時機。
(1)客戶端 WebView 回撥
基於 Android WebView 的過程監控回撥和頁面框架能力,可以實現的效能監控包括:
其中,
onMainFrameFinished
取第一個非主請求 (HTML) 的資源被攔截的時機。對於絕大多數頁面來說,此時已經完成主請求 (HTML) 的下載,並已經開始解析;可以粗略代表主請求流程結束。
(2)W3C Performance Timing
與客戶端回撥相比,W3C Performance Timing 提供了更細緻的載入過程資訊,但是不包含 WebView 開始初始化的時間點。下圖中僅列出部分:
2. 各端單獨採集的侷限
(1)前端採集的侷限
-
無法獨立獲取 WebView 開始初始化的時間點。
-
想獲取最精確的載入完成時間點,主要依賴手動埋點。
(2)客戶端採集的侷限
SSR (服務端渲染) 和 CSR (客戶端渲染),頁面內容可消費的時間點不一致。
對 WebView 頁面載入週期來說:
-
CSR 頁面需在前端頁面框架載入後再展示資料,內容請求完成並上屏,發生在頁面載入完成之後
-
SSR 頁面的首次內容上屏可攜帶首屏資料,因此在頁面載入完成之前,頁面內容已經可以被消費
客戶端回撥時機不夠完整或過於“苛刻”,測不準“頁面內容可消費”的時間點。
通過追溯客戶端 onPageFinished 的回撥時機,發現對應的 Blink 程式碼要求必須滿足:頁面解析完畢、 沒有正在下載的資源等條件。
按照這個標準,一旦存在某個圖片一直處在載入中,但頁面框架的其他內容均已處理完畢,onPageFinished 回撥也會等待圖片載入完成才回撥,與實際上的 “頁面內容可消費” 時間點存在差異。
3. 指標設計方案
結合上述分析,可以確定:
-
最準確的頁面載入完成時機來自前端
-
最準確的 WebView 初始化時機來自客戶端
因此,完善的耗時測量需由客戶端和前端協同完成。
(1)前端側
前端自行完成結束時間點的設定,並從客戶端獲取 WebView 初始化時間點,統計上報開啟耗時。
-
前端通過手動埋點或監聽 DOM 節點數變更,獲取載入完成時間點。
-
前端統計時呼叫客戶端提供 JSAPI,獲取以 WebView 初始化時間點作為起點的耗時。
-
並由前端完成載入耗時的計算和統計上報。
(2)客戶端側
作為一個補充方案,客戶端可以通過 JavaScript 注入獲取上述 W3C Performance Timing 中的 domInteractive 時間點,作為結束時間點。
前端
domInteractive
時,已完成所有頁面展示必需資源的請求和處理耗時的差異,可以體現任何頁面的客戶端通用優化效果
可以衡量SSR(服務端渲染) 頁面的可消費耗時,和CSR(客戶端渲染)頁面的首幀耗時
webView.evaluateJavascript(
script = “(function(){return performance.timing.domInteractive;})();”,
callback = { value ->
responseEndDuration = value.toLong() - getOnCreateTimestamp()
}
)
雖然 WebKit 負責維護 Performance Timing 的值,但是 WebView 並未提供介面獲取上述時間點的值。
三、優化方案和效果
1. 優化方案概述
基於客戶端內 Web 頁面的載入流程,從 “WebView 初始化耗時優化”、“資源載入耗時優化”、“邏輯處理耗時優化” 三個方面,提出了 5 個優化項。
-
TBS (X5 核心) 環境預載入
-
WebView 例項池
-
主請求並行載入
-
Web 公共資源池
-
跟膚邏輯優化
各優化項在 Web 頁面載入過程中的生效時機如下:
2. 優化手段說明
(1)WebView 初始化
經過前期分析,WebView 初始化耗時本身的耗時壓縮空間比較有限。因此優化手段主要以初始化邏輯前置為主。例如,“WebView 例項池” 通過在應用位於後臺、主執行緒卡頓影響不明顯的時機進行 WebView 預初始化,置換啟動 Web 頁面時的初始化耗時。
(2)客戶端自建快取
為了實現前述各項資源載入優化,客戶端需要獨立於 WebView 的快取機制,自建一個資源快取。
自建快取參考客戶端常用的三級快取機制,基於 WebView 的強生命週期,設計了 “冷-熱快取迴圈” 的快取生命週期。
例如,在 WebView 初始化的同時,自建快取把頁面需要的資源從檔案系統載入到記憶體;向 WebView 資源攔截回撥輸入位元組流時,自建快取一定從記憶體快取中輸出,輸出完畢後即可立即從記憶體快取中被清除。這一機制可以使記憶體快取的淘汰更積極,位元組流在記憶體中停留的時間更短,減少記憶體佔用。
(3)公共資源內聯
在完成公共資源池開發後,頁面開啟耗時出現了負優化的情況。經過分析,確定與資源攔截回撥的效能瓶頸有關。
-
單執行緒模型導致讀寫效能下降
-
被攔截資源的數量越多,對效能的影響越容易被放大
因此,為了減少資源攔截回撥的效能影響,從減少攔截次數的角度,引入了公共資源內聯優化。
-
公共資源載入到熱快取後,轉換為對應的 HTML 節點
-
主請求並行載入完成後,直接在主請求位元組流中替換其對應的外聯節點;替換後的新位元組流返回 WebView
引入公共資源內聯後,基本抵消了資源攔截回撥的效能影響,頁面載入耗時提升 3.2%。
3. 優化效果
QQ 音樂 Android 端內評論頁:
-
載入耗時降低 26.2% (1932ms → 1426ms)
-
跳出率降低
-
停留時長中位數增加
四、跨端場景的瓶頸與對策
基於在 WebView 場景下的優化過程,推及跨端場景可能存在的類似問題,本文嘗試給出一些跨端場景中可能的效能瓶頸及應對方式。
1. 前終端通訊通道效能不足,考慮 “少次多量”
跨平臺方案 (WebView、React Native 等) 普遍存在前終端通訊通道效能不足的問題。
-
WebView 通道不支援較大量級資料的傳遞
-
通訊執行緒多為單執行緒,甚至需要在主執行緒發起或處理通訊
-
對傳遞次數的敏感程度大於對傳遞資料總量的敏感程度
因此,當在跨端場景出現大資料量傳遞時,需要優先考慮當前通訊通道的可用性。在需要傳遞資料總量無法壓縮的情況下,如果通道允許,儘量減少傳遞次數,增加單次傳遞的資料量。
“公共資源內聯” 即是這一思路的實踐。
2. 擴充套件生命週期
前端生命週期有限。客戶端可以利用在前端生命週期以外的時間,進行適當的資源前置和邏輯前置,降低頁面載入耗時。
例如上述優化中的 “公共資源池”、“主請求並行載入” 等,體現了擴充套件生命週期的思想。除此之外,微信小程式的雙執行緒模型[1]通過引入 JSCore,增加前端程式碼的可執行時長,並通過離線包等手段幫助前端擴充套件生命週期。
3. 精簡 / 前置公共庫程式碼
如果前端頁面共用公共庫,隨著前端業務的複雜化,公共庫的自然膨脹,可能會放大指令碼解析與執行的耗時。
針對 Web 頁面,可以通過精簡基礎庫的方式,減少無關程式碼的執行;針對 React Native 頁面,可以通過進行分包和例項預載入,讓更多基礎庫程式碼在頁面載入前執行,從而降低頁面啟動時執行的程式碼量,減少耗時。
五、總結與展望
本文基於客戶端內 Web 頁面的載入特點,針對 WebView 初始化、資源載入和邏輯處理現狀中的問題和瓶頸,設計並實施了 5 個優化項,優化效果比較明顯。並且嘗試對跨端場景的瓶頸與對策進行歸納,嘗試為後續跨端場景的優化工作提供思路。
未來,團隊還將進一步豐富客戶端與前端的協同效能監控,並允許前端通過更精細化的方式啟動客戶端 Web 頁面框架。遠期,還將嘗試探索 CGI 前置、引入 JSCore 等手段,進一步提升特定場景下的 Web 頁面載入耗時。
參考資料:
[1] 微信小程式的雙執行緒模型:
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0000286f908988db00866b85f5640a
看騰訊技術,學雲端計算知識,關注雲加社群