老板說 , 頁面打開速度過慢? 頁面加載性能不達標? 下面我們來看下各個大廠和團隊的秒開經典方案,有沒有一款適合你去探索?
本頁面會列舉和總結偏向與客戶端結合的 hybrid
秒開方案,純前端方案也會部分提及。
常用的加速方法
說起 h5 性能優(yōu)化方案,是個老生常談的話題,通常的 web 優(yōu)化 方法,基本圍繞在資源加載和 htm 渲染兩個方面。前者針對首屏,后者針對可交互。資源優(yōu)化上,我們總的方向是圍繞更小的資源包上,比如常見的:壓縮、減包、拆包、動態(tài)加載包及圖片優(yōu)化上。html 渲染上總的方向是更快的展示內容,比如通過 cdn 分發(fā)、dns 解析、http 緩存、數(shù)據(jù)預請求,數(shù)據(jù)緩存及首屏優(yōu)化大殺器——直出等。
這些方案是各種前端面試中必考點,也是作為一個前端開發(fā),當遇到性能問題、需要解決性能問題時最為首要和基本的思路。而具體應該使用什么樣的方案,取決于實際開發(fā)需求、優(yōu)先級、綜合成本、及投入產出比等。
在 react-native、weex、及 flutter 等客戶端的技術不斷在沖擊傳統(tǒng) hybrid 的時候,hybrid 也在一路演化、加速,朝著一個使其達到與原生相媲美的方向發(fā)展。下面歸納了 hybrid 發(fā)展中出現(xiàn)的一些方案,排序不分先后。
直出+離線包緩存
為了優(yōu)化首屏,大部分主流的頁面會通過服務器進行渲染,吐出 html 文件到前端,解決轉菊花比較久的問題,不同類型的主流框架,都會有一套后臺渲染方案,比如 vue-server-renderer、react-dom/server 等。直出省去了前端渲染,及 ajax 請求的時間,雖然直出能夠通過各種緩存策略優(yōu)化得很好,但加載 html 仍然需要時間。
通過離線包技術能夠很好解決 html 文件本身加載需要時間的問題。離線包基本思路都是通過 webview 統(tǒng)一攔截 url,將資源映射到本地離線包,更新的時候對版本資源檢測,下載和維護本地緩存目錄中的資源。比如騰訊的 webso 和 Alloykit 的離線包方案。
離線包策略在很多大廠運用比較成熟,它對 web 端而言,是相對透明,侵入性非常小。
客戶端代理的 VasSonic
在 hybrid h5 中,用戶從點擊到看見頁面之間,還存在 webview 初始化,請求資源的時間,而這里的過程是串行的,對于追求更極致的體驗來說,這里是有優(yōu)化掉的空間和可能。 VasSonic 是騰訊增值會員團隊研發(fā)的一個輕量級 hybrid 框架,支持上面提到的離線包策略,更進一步的是,它還做了以下優(yōu)化:
- webview 初始化和通過客戶端代理資源請求并行
- 流式攔截請求,邊加載邊渲染
- 實現(xiàn)了動態(tài)緩存和增量更新。
簡單說下它是怎么做到的,客戶端代理資源請求并行沒什么好說的,就是在創(chuàng)建 webview 之前,通過客戶端代理建立網(wǎng)絡連接,請求 html,然后緩存起來,等待 webview 線程發(fā)起 html 資源請求的時候,客戶端進行攔截,將緩存好的 html 返回給 webview。
動態(tài)緩存和增量更新如何做到呢?
VasSonic 將 html 的內容分為 html 模板和動態(tài)數(shù)據(jù)兩部分,如何區(qū)分這兩種類型呢,它自己定義了一套 html 注釋標記規(guī)則,通過標簽劃分哪些是動態(tài)數(shù)據(jù),哪些是模板數(shù)據(jù)。然后再拓展了 http 頭部,定制了一套請求后臺的約定。webview 發(fā)起 http 請求時會將頁面內容的 id 攜帶過去,后臺處理判斷后,再告訴客戶端是否需要更新局部數(shù)據(jù),如果是則將緩存的 html 模板與新數(shù)據(jù)拼接成新的 html,最后計算出數(shù)據(jù)差異部分,通過 js 回調給頁面,進行布局刷新。
圖來源網(wǎng)絡
VasSonic 的方案整體思路和效果非常不錯,特別是對于大部分 web 場景,通常我們的模板較少發(fā)生變化,大部分是數(shù)據(jù)部分變化,能夠很好的通過局部刷新做到秒開效果。對于首次加載而言,通過并發(fā)請求和 webview 創(chuàng)建帶來了不錯的性能提升,還能無縫的支持離線包策略。
但是 VasSonic 定義了一套特殊的注釋標記及拓展了頭部,需要包括后臺在內的前后端進行改造,對 web 侵入性非常強,接入的工作量及維護成本會非常大。
PWA+直出+預加載
不管是離線包技術,還是 webview 代理請求,都是對前端侵入非常大的,pwa 作為 web 標準,能夠通過純 web 的方案去加速和優(yōu)化加載性能。
首先,pwa 的能夠通過 cacheStorage 緩存普通的圖片、js 、css 資源。另一方面,在傳統(tǒng)的 http cache 中,我們一般不會緩存 html,這是因為頁面一旦設置了過長的 max-age,在瀏覽器緩存過期時間內,用戶看到的永遠將是舊的。
如果使用了 pwa 的 html 頁面,能否直接緩存呢?由于 pwa 可精細化控制緩存,答案是可以的。
對于直出 html,我們可以配合 pwa,將從后臺直出的文件,緩存到 cacheStorage,在下一次請求時,優(yōu)先從本地緩存中獲取,同時發(fā)起網(wǎng)絡請求更新本地 html 文件。
但是在 hybrid 的 h5 應用,第一次啟動的加載資源仍然費時,我們可以通過 app 端上支持預加載一個 javascript 腳本,拉取需要 PWA 緩存的頁面,可以提前完成緩存。
對于非直出的頁面,我們仍然無法避免瀏覽器渲染 html 時間的問題,應該如何減少這里的時間呢?
這里明確兩個點,第一次永遠只能靠提前加載,所以上面的借助端上預加載腳本仍然生效;第二點非直出頁面,每個頁面需要有獨一無二的標記,比如 hash。瀏覽器獲取到數(shù)據(jù),并且渲染好的 html,能夠通過 outerHTML 方法,將 html 頁面緩存到 cacheStorage 中,第二次訪問優(yōu)先從本地獲取,同時發(fā)起 html 請求,通過對比其中唯一標識的差異,決定是否需要更新。
pwa 一系列方案替代離線包策略,帶來的好處是,屬于 web 標準,適用于普通能夠支持 service-worker 的 H5 頁面。在允許兼容問題允許的情況下,建議主加。
NSR 渲染
GMTC2019 全球大前端技術上 UC 團隊提到了 0.3 秒的 “閃開” 方案。NSR 就是前端版本的 SSR,非常具有啟發(fā)性。
其核心思路是,借助瀏覽器啟用一個 JS-Runtime,提前將下載好的 html 模板及預取的 feed 流數(shù)據(jù)進行渲染,然后將 html 設置到內存級別的 MemoryCache 中,從而達到點開即看的效果。
NSR 將 SSR 渲染的過程分發(fā)到了各個用戶的端中,在減少了后臺請求壓力的同時,也加進一步快了頁面打開速度,堪稱做到極致。
問題是數(shù)據(jù)預取和預渲染帶來額外的流量和性能開銷,特別是流量,如何更準確的預測用戶行為,提高命中率是非常重要的事。類似 NSR 的方案我們也在逐步探索中。
客戶端 PWA
在實際測試、及和瀏覽器團隊的同學了解和溝通中,service-worker 在 webview 實現(xiàn)性能并沒有想象中好。在某項目下掉 sw 后,整體大盤訪問速度整體反而提升上升了大概 300ms。 這對 hybrid 應用而言,就提出了一項新的思路和挑戰(zhàn),能否在客戶上實現(xiàn)一套基本的 service-worker api?從而達到和 web 標準相兼容。這里也只是一種思路和想法,有大量待探索的問題點,比如 webview sw 具體的性能現(xiàn)狀,未來的支持情況呢,自行實現(xiàn)的成本,及最終帶來的效果和價值等。
小程序化
小程序生態(tài)已經非常成熟了,各大廠也都已經推出了自己平臺的小程序,國內廠商也不斷在嘗試推進 MiniApp w3c 標準。不管從加載速度還是頁面流暢度小程序都要高于 H5 頁面,其原因是通過在架構上對開發(fā)進行規(guī)范化和約束化,小程序內部將 webview 渲染和 js 執(zhí)行分離開來,然后通過離線包,頁面拆分,預加載頁面等一系列優(yōu)化手段,讓小程序天然具備了大量的 H5 優(yōu)化后的效果,其代價是犧牲了 web 的靈活性。但對于 hybrid 開發(fā),通過原生客戶端底層支持這種小程序環(huán)境,然后大量業(yè)務邏輯采用小程序方案開發(fā),來達到迭代速度與性能兼并的效果,是一種非常不錯的方向。
結
本文主要總結了這幾天大量閱讀梳理十幾篇關于秒開的文章和及最近的一些思考與實踐,從中提取出了部分具有代表性的方案。 不管哪種類型的方案,發(fā)現(xiàn)其總的思路和方向都是:
- 在整個鏈路中減少中間環(huán)節(jié)。比如將串行改并行,包括小程序內部執(zhí)行機制。
- 盡可能的預加載、預執(zhí)行。比如從數(shù)據(jù)預取,到頁面預取渲染等。
任何轉換都有代價,加速本質上就是在用更多的網(wǎng)絡、內存和 CPU 換取速度,以空間換時間。
參考:
相關閱讀:
作者:flyfu wang
來源:AlloyTeam