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