英泰移動(dòng)通信教育

7x24小時(shí)咨詢熱線

400-660-3310

當(dāng)前位置 : 好學(xué)校 英泰移動(dòng)通信教育 學(xué)習(xí)資訊 資訊詳情

客戶端H5前端優(yōu)化方案

2021-11-24

桌面時(shí)代受限于瀏覽器,H5 頁面無法做更多的優(yōu)化,現(xiàn)在 H5 頁面是內(nèi)嵌在客戶端 APP 上,客戶端有更多的權(quán)限,于是客戶端上可以超出瀏覽器的范圍,做更多的優(yōu)化。

程序員

HTML 緩存

先接著緩存說,在客戶端有更自由的緩存策略,客戶端可以攔截 H5 頁面的所有請(qǐng)求,由自己管理緩存,針對(duì)上述 HTML 文件的“緩存”和“更新”之間的矛盾,我們可以用這樣的策略解決:

在客戶端攔截請(qǐng)求,第1次請(qǐng)求 HTML 文件后緩存數(shù)據(jù),第二次不發(fā)請(qǐng)求,直接使用緩存數(shù)據(jù)。

什么時(shí)候去請(qǐng)求更新?這個(gè)更新請(qǐng)求可以客戶端自由控制策略,可以在使用本地緩存打開本地頁面后再在后臺(tái)發(fā)起請(qǐng)求詢問更新緩存,下次打開時(shí)生效;也可以在 APP 啟動(dòng)時(shí)或某個(gè)時(shí)機(jī)在后臺(tái)去發(fā)起請(qǐng)求預(yù)更新,提升用戶訪問醉新代碼的幾率。

這樣看起來已經(jīng)比較完美了,HTML 文件在用客戶端的策略緩存,其余資源和數(shù)據(jù)沿用上述前端的緩存方式,這樣一個(gè) H5 頁面第二次訪問從 HTML 到 JS/CSS/Image 資源,再到數(shù)據(jù),都可以直接從本地讀取,無需等待網(wǎng)絡(luò)請(qǐng)求,同時(shí)又能保持盡可能的實(shí)時(shí)更新,解決了緩存問題,大大提升 H5 頁面首屏啟動(dòng)速度。

問題

上述方案似乎已完整解決緩存問題,但實(shí)際上還有很多問題:

沒有預(yù)加載:第1次打開的體驗(yàn)很差,所有數(shù)據(jù)都要從網(wǎng)絡(luò)請(qǐng)求。

緩存不可控:緩存的存取由系統(tǒng) webview 控制,無法控制它的緩存邏輯,帶來的問題包括: 1. 清理邏輯不可控,緩存空間有限,可能緩存幾張大圖片后,重要的 HTML/JS/CSS 緩存就被清除了。 2.磁盤 IO 無法控制,無法從磁盤預(yù)加載數(shù)據(jù)到內(nèi)存。

更新體驗(yàn)差:后臺(tái) HTML/JS/CSS 更新時(shí)全量下載,數(shù)據(jù)量大,弱網(wǎng)下載耗時(shí)長。

無法防劫持:若 HTML 頁面被運(yùn)營商或其他第三方劫持,將長時(shí)間緩存劫持的頁面。

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

可以配置一個(gè)預(yù)加載列表,在APP啟動(dòng)或某些時(shí)機(jī)時(shí)提前去請(qǐng)求,這個(gè)預(yù)加載列表需要包含所需 H5 模塊的頁面和資源,還需要考慮到一個(gè)H5模塊有多個(gè)頁面的情況,這個(gè)列表可能會(huì)很大,也需要工具生成和管理這個(gè)預(yù)加載列表。

客戶端可以接管所有請(qǐng)求的緩存,不走 webview 默認(rèn)緩存邏輯,自行實(shí)現(xiàn)緩存機(jī)制,可以分緩存優(yōu)先級(jí)以及緩存預(yù)加載。

可以針對(duì)每個(gè) HTML 和資源文件做增量更新,只是實(shí)現(xiàn)和管理起來比較麻煩。

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

上面的解決方案實(shí)現(xiàn)起來十分繁瑣,原因就是各個(gè) HTML 和資源文件很多很分散,管理困難,有個(gè)較好的方案可以解決這些問題,就是離線包。

離線包

既然很多問題都是文件分散管理困難引起,而我們這里的使用場景是使用 H5 開發(fā)功能模塊,那很容易想到把一個(gè)個(gè)功能模塊的所有相關(guān)頁面和資源打包下發(fā),這個(gè)壓縮包可以稱為功能模塊的離線包。使用離線包的方案,可以相對(duì)較簡單地解決上述幾個(gè)問題:

可以預(yù)先下載整個(gè)離線包,只需要按業(yè)務(wù)模塊配置,不需要按文件配置,離線包包含業(yè)務(wù)模塊相關(guān)的所有頁面,可以一次性預(yù)加載。

離線包核心文件和頁面動(dòng)態(tài)的圖片資源文件緩存分離,可以更方便地管理緩存,離線包也可以整體提前加載進(jìn)內(nèi)存,減少磁盤 IO 耗時(shí)。

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

離線包以壓縮包的方式下發(fā),同時(shí)會(huì)經(jīng)過加密和校驗(yàn),運(yùn)營商和第三方無法對(duì)其劫持篡改。

到這里,對(duì)于使用 H5 開發(fā)功能模塊,離線包是一個(gè)挺不錯(cuò)的方案了,簡單復(fù)述一下離線包的方案:

后端使用構(gòu)建工具把同一個(gè)業(yè)務(wù)模塊相關(guān)的頁面和資源打包成一個(gè)文件,同時(shí)對(duì)文件加密/簽名。

客戶端根據(jù)配置表,在自定義時(shí)機(jī)去把離線包拉下來,做解壓/解密/校驗(yàn)等工作。

根據(jù)配置表,打開某個(gè)業(yè)務(wù)時(shí)轉(zhuǎn)接到打開離線包的入口頁面。

攔截網(wǎng)絡(luò)請(qǐng)求,對(duì)于離線包已經(jīng)有的文件,直接讀取離線包數(shù)據(jù)返回,否則走 HTTP 協(xié)議緩存邏輯。

離線包更新時(shí),根據(jù)版本號(hào)后臺(tái)下發(fā)兩個(gè)版本間的 diff 數(shù)據(jù),客戶端合并,增量更新。

更多優(yōu)化

離線包方案在緩存上已經(jīng)做得差不多了,還可以再配上一些細(xì)節(jié)優(yōu)化:

公共資源包

每個(gè)包都會(huì)使用相同的 JS 框架和 CSS 全局樣式,這些資源重復(fù)在每一個(gè)離線包出現(xiàn)太浪費(fèi),可以做一個(gè)公共資源包提供這些全局文件。

預(yù)加載 webview

無論是 iOS 還是 Android,本地 webview 初始化都要不少時(shí)間,可以預(yù)先初始化好 webview。這里分兩種預(yù)加載:

預(yù)加載:在一個(gè)進(jìn)程內(nèi)初始化 webview 與第二次初始化不同,第1次會(huì)比第二次慢很多。原因預(yù)計(jì)是 webview 第1次初始化后,即使 webview 已經(jīng)釋放,但一些多 webview 共用的全局服務(wù)或資源對(duì)象仍沒有釋放,第二次初始化時(shí)不需要再生成這些對(duì)象從而變快。我們可以在 APP 啟動(dòng)時(shí)預(yù)先初始化一個(gè) webview 然后釋放,這樣等用戶真正走到 H5 模塊去加載 webview時(shí)就變快了。

webview 池:可以用兩個(gè)或多個(gè) webview 重復(fù)使用,而不是每次打開 H5 都新建 webview。不過這種方式要解決頁面跳轉(zhuǎn)時(shí)清空上一個(gè)頁面,另外若一個(gè) H5 頁面上 JS 出現(xiàn)內(nèi)存泄漏,就影響到其他頁面,在 APP 運(yùn)行期間都無法釋放了。

可以參考美團(tuán)點(diǎn)評(píng)的這篇文章。

預(yù)加載數(shù)據(jù)

理想情況下離線包的方案第1次打開時(shí)所有 HTML/JS/CSS 都使用本地緩存,無需等待網(wǎng)絡(luò)請(qǐng)求,但頁面上的用戶數(shù)據(jù)還是需要實(shí)時(shí)拉,這里可以做個(gè)優(yōu)化,在 webview 初始化的同時(shí)并行去請(qǐng)求數(shù)據(jù),webview 初始化是需要一些時(shí)間的,這段時(shí)間沒有任何網(wǎng)絡(luò)請(qǐng)求,在這個(gè)時(shí)機(jī)并行請(qǐng)求可以節(jié)省不少時(shí)間。

具體實(shí)現(xiàn)上,首先可以在配置表注明某個(gè)離線包需要預(yù)加載的 URL,客戶端在 webview 初始化同時(shí)發(fā)起請(qǐng)求,請(qǐng)求由一個(gè)管理器管理,請(qǐng)求完成時(shí)緩存結(jié)果,然后 webview 在初始化完畢后開始請(qǐng)求剛才預(yù)加載的 URL,客戶端攔截到請(qǐng)求,轉(zhuǎn)接到剛才提到的請(qǐng)求管理器,若預(yù)加載已完成就直接返回內(nèi)容,若未完成則等待。

Fallback

如果用戶訪問某個(gè)離線包模塊時(shí),這個(gè)離線包還沒有下載,或配置表檢測到已有新版本但本地是舊版本的情況如何處理?幾種方案:

簡單的方案是如果本地離線包沒有或不是醉新,就同步阻塞等待下載醉新離線包。這種用戶打開的體驗(yàn)更差了,因?yàn)殡x線包體積相對(duì)較大。

也可以是如果本地有舊包,用戶本次就直接使用舊包,如果沒有再同步阻塞等待,這種會(huì)導(dǎo)致更新不及時(shí),無法確保用戶使用醉新版本。

還可以對(duì)離線包做一個(gè)線上版本,離線包里的文件在服務(wù)端有一一對(duì)應(yīng)的訪問地址,在本地沒有離線包時(shí),直接訪問對(duì)應(yīng)的線上地址,跟傳統(tǒng)打開一個(gè)在線頁面一樣,這種體驗(yàn)相對(duì)等待下載整個(gè)離線包較好,也能**用戶訪問到醉新。

第三種 Fallback 的方式還帶來兜底的好處,在一些意外情況離線包出錯(cuò)的時(shí)候可以直接訪問線上版本,功能不受影響,此外像公共資源包更新不及時(shí)導(dǎo)致版本沒有對(duì)應(yīng)上時(shí)也可以直接訪問線上版本,是個(gè)不錯(cuò)的兜底方案。

上述幾種方案策略也可以混著使用,看業(yè)務(wù)需求。

使用客戶端接口

網(wǎng)路和存儲(chǔ)接口如果使用 webkit 的 ajax 和 localStorage 會(huì)有不少限制,難以優(yōu)化,可以在客戶端提供這些接口給 JS,客戶端可以在網(wǎng)絡(luò)請(qǐng)求上做像 DNS 預(yù)解析/IP直連/長連接/并行請(qǐng)求等更細(xì)致的優(yōu)化,存儲(chǔ)也使用客戶端接口也能做讀寫并發(fā)/用戶隔離等針對(duì)性優(yōu)化。

服務(wù)端渲染

早期 web 頁面里,JS 只是負(fù)責(zé)交互,所有內(nèi)容都是直接在 HTML里,到現(xiàn)代 H5 頁面,很多內(nèi)容已經(jīng)依賴 JS 邏輯去決定渲染什么,例如等待 JS 請(qǐng)求 JSON 數(shù)據(jù),再拼接成 HTML 生成 DOM 渲染到頁面上,于是頁面的渲染展現(xiàn)就要等待這一整個(gè)過程,這里有一個(gè)耗時(shí),減少這里的耗時(shí)也是白屏優(yōu)化的范圍之內(nèi)。

優(yōu)化方法可以是人為減少 JS 渲染邏輯,也可以是更徹底地,回歸到原始,所有內(nèi)容都由服務(wù)端返回的 HTML 決定,無需等待 JS 邏輯,稱之為服務(wù)端渲染。是否做這種優(yōu)化視業(yè)務(wù)情況而定,畢竟這種會(huì)帶來開發(fā)模式變化/流量增大/服務(wù)端開銷增大這些負(fù)面影響。

收藏
分享到:

相關(guān)課程

相關(guān)資訊

英泰移動(dòng)通信教育

英泰移動(dòng)通信教育

認(rèn)證等級(jí)

信譽(yù)良好,可安心報(bào)讀

英泰移動(dòng)通信教育

已獲好學(xué)校V2信譽(yù)等級(jí)認(rèn)證

信譽(yù)值

  • (60-80)基礎(chǔ)信譽(yù)積累,可放心報(bào)讀
  • (81-90)良好信譽(yù)積累,可持續(xù)信賴
  • (91-100)充分信譽(yù)積累,推薦報(bào)讀

與好學(xué)校簽訂讀書保障協(xié)議:

  • 100%
  • 54
  • 3390
在線咨詢
;