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