使用H5做app啟動頁優化

2021-08-07 19:57:43 字數 4470 閱讀 4579

雖然說 h5 頁面效能變好了,但如果沒針對性地做一些優化,體驗還是很糟糕的,主要兩部分體驗:

響應流暢度:由於 webkit 的渲染機制,單執行緒,歷史包袱等原因,頁面重新整理/互動的效能體驗不如原生。

為什麼開啟乙個 h5 頁面會有一長段白屏時間?因為它做了很多事情,大概是:

一些簡單的頁面可能沒有 js 請求資料 這一步,但大部分功能模組應該是有的,根據當前使用者資訊,js 向後台請求相關資料再渲染,是常規開發方式。

上述開啟乙個頁面的過程有很多優化點,包括前端和客戶端,常規的前端和後端的效能優化在桌面時代已經有最佳實踐,主要的是:

降低請求量:合併資源,減少 http 請求數,minify / gzip 壓縮,webp,lazyload。

加快請求速度:預解析dns,減少網域名稱數,並行載入,cdn 分發。

快取:http 協議快取請求,離線快取 manifest,離線資料快取localstorage。

渲染:js/css優化,載入順序,服務端渲染,pipeline。

其中對首屏啟動速度影響最大的就是網路請求,所以優化的重點就是快取,這裡著重說一下前端對請求的快取策略。我們再細分一下,分成 html 的快取,js/css/image 資源的快取,以及 json 資料的快取。

html 和 js/css/image 資源都屬於靜態檔案,http 本身提供了快取協議,瀏覽器實現了這些協議,可以做到靜態檔案的快取,具體可以參考這裡,總的來說,就是兩種快取:

詢問是否有更新:根據 if-modified-since / etag 等協議向後端請求詢問是否有更新,沒有更新返回304,瀏覽器使用本地快取。

直接使用本地快取:根據協議裡的 cache-control / expires 欄位去確定多長時間內可以不去發請求詢問更新,直接使用本地快取。

前端能做的最大限度的快取策略是:html 檔案每次都向伺服器詢問是否有更新,js/css/image資源檔案則不請求更新,直接使用本地快取。那 js/css 資源檔案如何更新?常見做法是在在構建過程中給每個資源檔案乙個版本號或hash值,若資源檔案有更新,版本號和 hash 值變化,這個資源請求的 url 就變化了,同時對應的 html 頁面更新,變成請求新的資源url,資源也就更新了。

json 資料的快取可以用 localstorage 快取請求下來的資料,可以在首次顯示時先用本地資料,再請求更新,這都由前端 js 控制。

這些快取策略可以實現 js/css 等資源檔案以及使用者資料的快取的全快取,可以做到每次都直接使用本地快取資料,不用等待網路請求。但 html 檔案的快取做不到,對於 html 檔案,如果把 expires / max-age 時間設長了,長時間只使用本地快取,那更新就不及時,如果設短了,每次開啟頁面都要發網路請求詢問是否有更新,再確定是否使用本地資源,一般前端在這裡的策略是每次都請求,這在弱網情況下使用者感受到的白屏時間仍然會很長。所以 html 檔案的「快取」和跟「更新」間存在矛盾。

先接著快取說,在客戶端有更自由的快取策略,客戶端可以攔截 h5 頁面的所有請求,由自己管理快取,針對上述 html 檔案的「快取」和「更新」之間的矛盾,我們可以用這樣的策略解決:

在客戶端攔截請求,首次請求 html 檔案後快取資料,第二次不發請求,直接使用快取資料。

這樣看起來已經比較完美了,html 檔案在用客戶端的策略快取,其餘資源和資料沿用上述前端的快取方式,這樣乙個 h5 頁面第二次訪問從 html 到 js/css/image 資源,再到資料,都可以直接從本地讀取,無需等待網路請求,同時又能保持盡可能的實時更新,解決了快取問題,大大提公升 h5 頁面首屏啟動速度。

上述方案似乎已完整解決快取問題,但實際上還有很多問題:

沒有預載入:第一次開啟的體驗很差,所有資料都要從網路請求。

快取不可控:快取的訪問由系統 webview 控制,無法控制它的快取邏輯,帶來的問題包括: i. 清理邏輯不可控,快取空間有限,可能快取幾張大後,重要的 html/js/css 快取就被清除了。 ii.磁碟 io 無法控制,無法從磁碟預載入資料到記憶體。

無法防劫持:若 html 頁面被運營商或其他第三方劫持,將長時間快取劫持的頁面。

這些問題在客戶端上都是可以被解決的,只不過有點麻煩,簡單描述下:

客戶端可以接管所有請求的快取,不走 webview 預設快取邏輯,自行實現快取機制,可以分快取優先順序以及快取預載入。

可以針對每個 html 和資源檔案做增量更新,只是實現和管理起來比較麻煩。

在客戶端使用 httpdns + https 防劫持。

上面的解決方案實現起來十分繁瑣,原因就是各個 html 和資源檔案很多很分散,管理困難,有個較好的方案可以解決這些問題,就是離線包。

既然很多問題都是檔案分散管理困難引起,而我們這裡的使用場景是使用 h5 開發功能模組,那很容易想到把乙個個功能模組的所有相關頁面和資源打包下發,這個壓縮包可以稱為功能模組的離線包。使用離線包的方案,可以相對較簡單地解決上述幾個問題:

離線包核心檔案和頁面動態的資源檔案快取分離,可以更方便地管理快取,離線包也可以整體提前載入進記憶體,減少磁碟 io 耗時。

離線包可以很方便地根據版本做增量更新。

離線包以壓縮包的方式下發,同時會經過加密和校驗,運營商和第三方無法對其劫持篡改。

到這裡,對於使用 h5 開發功能模組,離線包是乙個挺不錯的方案了,簡單複述一下離線包的方案:

後端使用構建工具把同乙個業務模組相關的頁面和資源打包成乙個檔案,同時對檔案加密/簽名。

客戶端根據配置表,在自定義時機去把離線包拉下來,做解壓/解密/校驗等工作。

根據配置表,開啟某個業務時轉接到開啟離線包的入口頁面。

攔截網路請求,對於離線包已經有的檔案,直接讀取離線包資料返回,否則走 http 協議快取邏輯。

離線包更新時,根據版本號後台下發兩個版本間的 diff 資料,客戶端合併,增量更新。

公共資源包

每個包都會使用相同的 js 框架和 css 全域性樣式,這些資源重複在每乙個離線包出現太浪費,可以做乙個公共資源包提供這些全域性檔案。

預載入 webview

無論是 ios 還是 android,本地 webview 初始化都要不少時間,可以預先初始化好 webview。這裡分兩種預載入:

可以參考美團點評的這篇文章。

預載入資料

理想情況下離線包的方案第一次開啟時所有 html/js/css 都使用本地快取,無需等待網路請求,但頁面上的使用者資料還是需要實時拉,這裡可以做個優化,在 webview 初始化的同時並行去請求資料,webview 初始化是需要一些時間的,這段時間沒有任何網路請求,在這個時機並行請求可以節省不少時間。

具體實現上,首先可以在配置表註明某個離線包需要預載入的 url,客戶端在 webview 初始化同時發起請求,請求由乙個管理器管理,請求完成時快取結果,然後 webview 在初始化完畢後開始請求剛才預載入的 url,客戶端攔截到請求,轉接到剛才提到的請求管理器,若預載入已完成就直接返回內容,若未完成則等待。

fallback

也可以是如果本地有舊包,使用者本次就直接使用舊包,如果沒有再同步阻塞等待,這種會導致更新不及時,無法確保使用者使用最新版本。

第三種 fallback 的方式還帶來兜底的好處,在一些意外情況離線包出錯的時候可以直接訪問線上版本,功能不受影響,此外像公共資源包更新不及時導致版本沒有對應上時也可以直接訪問線上版本,是個不錯的兜底方案。

上述幾種方案策略也可以混著使用,看業務需求。

使用客戶端介面

網路和儲存介面如果使用 webkit 的 ajax 和 localstorage 會有不少限制,難以優化,可以在客戶端提供這些介面給 js,客戶端可以在網路請求上做像 dns 預解析/ip直連/長連線/並行請求等更細緻的優化,儲存也使用客戶端介面也能做讀寫併發/使用者隔離等針對性優化。

服務端渲染

早期 web 頁面裡,js 只是負責互動,所有內容都是直接在 html 裡,到現代 h5 頁面,很多內容已經依賴 js 邏輯去決定渲染什麼,例如等待 js 請求 json 資料,再拼接成 html 生成 dom 渲染到頁面上,於是頁面的渲染展現就要等待這一整個過程,這裡有乙個耗時,減少這裡的耗時也是白屏優化的範圍之內。

優化方法可以是人為減少 js 渲染邏輯,也可以是更徹底地,回歸到原始,所有內容都由服務端返回的 html 決定,無需等待 js 邏輯,稱之為服務端渲染。是否做這種優化視業務情況而定,畢竟這種會帶來開發模式變化/流量增大/服務端開銷增大這些負面影響。手q的部分頁面就是使用服務端渲染的方式,稱為動態直出,見文章。

從前端優化,到客戶端快取,到離線包,到更多的細節優化,做到上述這些點,h5 頁面在啟動上差不多可以媲美原生的體驗了。

總結起來,大體優化思路就是:快取/預載入/並行,快取一切網路請求,盡量在使用者開啟之前就載入好所有內容,能並行做的事不序列做。這裡有些優化手段需要做好一整套工具和流程支援,需要跟開發效率權衡,視實際需求優化。

這裡討論了 h5 頁面首屏啟動時間的優化,上述優化過後,基本上耗時只剩 webview 本身的啟動/渲染機制問題了,這個問題跟後續的響應流暢度的問題一起屬於另乙個優化範圍,就是類 rn / weex 這樣的方案,有機會再**。

h5頁面啟動安卓應用 h5啟動原生APP總結

1 客戶端判斷 所以首先要在客戶端判斷,是android系統還是ios系統,判斷 如下 function isinios elseelse 2000 var t1 date.now window.location.href wushang android var t2 date.now t 四 io...

h5頁面啟動安卓應用 h5啟動原生APP總結

1 客戶端判斷 所以首先要在客戶端判斷,是android系統還是ios系統,判斷 如下 functionisinios return false functionisinwx elseelse 2000 var t1 date.now window.location.href wushang and...

H5頁面效能優化

對於乙個產品,效能在使用者體驗中是必不可缺的一環。效能優化是個長遠的事情,聯想到導航專案,列出以下效能優化的方案 一.基本的 層面優化 1 合理使用css 1 正確使用display屬性 display屬性會影響頁面的渲染,因此請合理使用 2 display inline後不應該再使用width h...