QQ音樂 Android 客戶端的 Web 頁面日均 PV 達到千萬量級,然而頁面的打開耗時與 Native 頁面相距甚遠,須要系統性優化。本文將介紹 QQ 音樂 Android 客戶端在進行 Web 頁面通用性能優化過程當中的問題、思路、方案和效果,並嘗試對跨端場景的常見瓶頸和對策進行概括。文章做者:關岳,QQ音樂客戶端開發工程師。
做爲一款注重於內容運營的應用程序,QQ 音樂 Android 客戶端的 Web 頁面日均 PV 達到千萬量級,評論頁、MV 頁等核心頁面均有 Web 頁面參與,或徹底由 Web 實現。前端
客戶端內 Web 頁面的打開耗時與 Native 頁面相距甚遠,須要系統性優化。然而,現有的前端和跨端優化方案,存在必定侷限性。web
針對 Web 頁面的耗時優化,在優化思路、方案、服務、工具鏈等方面都已經建設得很是詳細。然而,在客戶端內 Web 頁面這一場景,純前端優化存在如下兩個侷限:小程序
從客戶端角度,除了思考優化 WebView 初始化耗時以外,還能夠從 「擴展前端生命週期」 的角度出發,思考優化方案。微信小程序
現有跨端優化方案,包括離線包、VasSonic 等,爲了達到最好的優化效果,均須要前端終端共同參與改造。這致使存量頁面的邏輯改造增長,對線上頁面不夠友好,引入額外的成本和風險。在前端開發資源不足時,這些優化的開展存在必定難度。緩存
從減小前端開發工做量的角度來看,須要思考更具通用性、前端感知更小的優化方案。性能優化
基於本次優化的背景,本次優化提出如下兩方面的目標:加強通用性、減小前端改形成本。微信
在展開優化思路和實施的同時,須要創建衡量優化效果的性能指標。框架
接下來基於客戶端內 Web 頁面加載過程,描述客戶端現有性能指標表明的時機。dom
基於 Android WebView 的過程監控回調和頁面框架能力,能夠實現的性能監控包括:前端優化
其中,
onMainFrameFinished
取第一個非主請求 (HTML) 的資源被攔截的時機。對於絕大多數頁面來講,此時已經完成主請求 (HTML) 的下載,並已經開始解析;能夠粗略表明主請求流程結束。
與客戶端回調相比,W3C Performance Timing 提供了更細緻的加載過程信息,可是不包含 WebView 開始初始化的時間點。下圖中僅列出部分:
SSR (服務端渲染) 和 CSR (客戶端渲染),頁面內容可消費的時間點不一致。
對 WebView 頁面加載週期來講:
客戶端回調時機不夠完整或過於「苛刻」,測不許「頁面內容可消費」的時間點。
經過追溯客戶端 onPageFinished 的回調時機,發現對應的 Blink 代碼要求必須知足:頁面解析完畢、 沒有正在下載的資源等條件。
按照這個標準,一旦存在某個圖片一直處在加載中,但頁面框架的其餘內容均已處理完畢,onPageFinished 回調也會等待圖片加載完成纔回調,與實際上的 「頁面內容可消費」 時間點存在差別。
結合上述分析,能夠肯定:
所以,完善的耗時測量需由客戶端和前端協同完成。
前端自行完成結束時間點的設置,並從客戶端獲取 WebView 初始化時間點,統計上報打開耗時。
做爲一個補充方案,客戶端能夠經過 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 並未提供接口獲取上述時間點的值。
基於客戶端內 Web 頁面的加載流程,從 「WebView 初始化耗時優化」、「資源加載耗時優化」、「邏輯處理耗時優化」 三個方面,提出了 5 個優化項。
各優化項在 Web 頁面加載過程當中的生效時機以下:
通過前期分析,WebView 初始化耗時自己的耗時壓縮空間比較有限。所以優化手段主要以初始化邏輯前置爲主。例如,「WebView 實例池」 經過在應用位於後臺、主線程卡頓影響不明顯的時機進行 WebView 預初始化,置換啓動 Web 頁面時的初始化耗時。
爲了實現前述各項資源加載優化,客戶端須要獨立於 WebView 的緩存機制,自建一個資源緩存。
自建緩存參考客戶端經常使用的三級緩存機制,基於 WebView 的強生命週期,設計了 「冷-熱緩存循環」 的緩存生命週期。
例如,在 WebView 初始化的同時,自建緩存把頁面須要的資源從文件系統加載到內存;向 WebView 資源攔截回調輸入字節流時,自建緩存必定從內存緩存中輸出,輸出完畢後便可當即從內存緩存中被清除。這一機制可使內存緩存的淘汰更積極,字節流在內存中停留的時間更短,減小內存佔用。
在完成公共資源池開發後,頁面打開耗時出現了負優化的狀況。通過分析,肯定與資源攔截回調的性能瓶頸有關。
所以,爲了減小資源攔截回調的性能影響,從減小攔截次數的角度,引入了公共資源內聯優化。
引入公共資源內聯後,基本抵消了資源攔截回調的性能影響,頁面加載耗時提高 3.2%。
QQ 音樂 Android 端內評論頁:
基於在 WebView 場景下的優化過程,推及跨端場景可能存在的相似問題,本文嘗試給出一些跨端場景中可能的性能瓶頸及應對方式。
跨平臺方案 (WebView、React Native 等) 廣泛存在前終端通訊通道效能不足的問題。
所以,當在跨端場景出現大數據量傳遞時,須要優先考慮當前通訊通道的可用性。在須要傳遞數據總量沒法壓縮的狀況下,若是通道容許,儘可能減小傳遞次數,增長單次傳遞的數據量。
「公共資源內聯」 便是這一思路的實踐。
前端生命週期有限。客戶端能夠利用在前端生命週期之外的時間,進行適當的資源前置和邏輯前置,下降頁面加載耗時。
例如上述優化中的 「公共資源池」、「主請求並行加載」 等,體現了擴展生命週期的思想。除此以外,微信小程序的雙線程模型[1]經過引入 JSCore,增長前端代碼的可執行時長,並經過離線包等手段幫助前端擴展生命週期。
若是前端頁面共用公共庫,隨着前端業務的複雜化,公共庫的天然膨脹,可能會放大腳本解析與執行的耗時。
針對 Web 頁面,能夠經過精簡基礎庫的方式,減小無關代碼的執行;針對 React Native 頁面,能夠經過進行分包和實例預加載,讓更多基礎庫代碼在頁面加載前執行,從而下降頁面啓動時執行的代碼量,減小耗時。
本文基於客戶端內 Web 頁面的加載特色,針對 WebView 初始化、資源加載和邏輯處理現狀中的問題和瓶頸,設計並實施了 5 個優化項,優化效果比較明顯。而且嘗試對跨端場景的瓶頸與對策進行概括,嘗試爲後續跨端場景的優化工做提供思路。
將來,團隊還將進一步豐富客戶端與前端的協同性能監控,並容許前端經過更精細化的方式啓動客戶端 Web 頁面框架。遠期,還將嘗試探索 CGI 前置、引入 JSCore 等手段,進一步提高特定場景下的 Web 頁面加載耗時。
參考資料:
[1] 微信小程序的雙線程模型:
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0000286f908988db00866b85f5640a
看騰訊技術,學雲計算知識,關注雲加社區