QQ音樂Android客戶端Web頁面通用效能優化實踐
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
看騰訊技術,學雲端計算知識,關注雲加社群