總結了下幾篇文章
網易(資源離線/JsBridge通信/接口預請求)
- 網易新聞客戶端H5秒開優化
- H5優勢: 跨平臺, 實時更新, 便於傳播等
- 劣勢: 功能(硬件訪問能力, 離線功能), 性能, 體驗等
一. 資源離線
-
靜態資源加載耗時, 資源離線到本地, 能很好解決.
-
web頁面把靜態資源生成zip包, 客戶端在合適的時機拉去zip包並解壓到本地, 持久化存儲.
-
用戶訪問的時候攔截WebView發出去的頁面請求, 直接返回對應的本地文件.
-
前端:
- 生成zip包 -> 更新離線數據
-
APP:
- 下載zip包 -> 攔截頁面請求 -> 返回本地資源
-
三個關鍵部分:
- Web頁面Zip包生成工具
- 離線管理系統
- 客戶端離線實現
-
web打包工具
{
[
"name": "index", // 頁面名稱
"url": ["https://example.com/index"] //頁面線上地址
"zipUrl": "https://assets.example.com/static/example.20190525_1020.zip", // zip地址
"md5": "md5md5md5md5md5md5md5md5md5md5md5md5" // md5
]
}
-
工具自動化分成通過中間件實現
-
通用部分:
- 拷貝頁面依賴, 生成zip包
- 判斷包的完整性
- 獲取zip包的md5值
- 生成zip包版本號
-
定製部分:
- 確定待更新zip包
- 上傳zip包到cdn
- 更新離線數據, zip包版本數據
-
通用部分:
- 獲取打包配置 -> 拷貝/打包 -> 檢測包完整性 -> 獲取MD5
-
定製部分: (可以在打包工具做, 也可以手動上傳)
- 確定待更新包 -> 上傳zip到cdn -> 更新數據
-
離線管理系統:
- 爲離線工具提供打包信息及離線包信息存儲
- 爲App提供離線數據
- 頁面離線數據在線管理
-
應該完成多產品, 多用戶設計.
-
工具自動更新數據, 還可以在系統裏添加數據, 對數據進行增刪改查.
-
離線數據保留最近5個版本, 發現線上zip包有問題, 可以迅速回歸.
-
核心功能:
- 多產品
- 多用戶
- 在線操作
- 提供接口
-
客戶端實現 (最重要)
- 離線資源更新
- 攔截資源返回
-
離線資源管理器總調度處理資源更新和攔截返回.
-
根據配置離線配置細膩創建動態管理器, 部署每個url對應的頁面入口文件, 靜態資源目錄等.
-
更新app配置氛圍主動和被動.
- 主動通過app啓動後通過接口獲取離線配置信息.
- 被動通過push更新.
-
獲取離線配置後, 讀取本地配置緩存進行對比.
-
根據頁面名稱確定離線文件的更新策略是什麼.
- 遠端配置無, 本地配置有, 認爲當前頁面離線包被刪除. 直接刪除本地對應的離線頁面入口文件.
- 發現兩個配置中同名頁面zip包的md5不一致, 認爲應該更新了.
- 如果發現遠端有, 本地無, 則是新增, 然後交給下載管理器下載. 下載解壓完成後, 通知管理器更新本地配置.
-
流程:
- 獲取離線配置 -> 匹配資源 -> 確定更新策略 -> 更新資源和本地配置.
-
攔截返回細節.
- 統一攔截所有網絡請求, 通過管理器處理訪問邏輯.
-
需要攔截返回:
- html
- js, css, img
-
app在WebView發起請求時, 會攔截當前頁面請求, 獲取頁面的URL地址, 根據管理器中的配置, 進行查找.
- 找到直接返回入口文件
- 未找到請求線上地址
-
頁面的加載會伴隨着依賴資源的加載, 獲取請求url, 如果在攔截域名內, 則替換域名爲本地的靜態資源目錄進行查找.
-
找到後, 獲取文件擴展名, 設置返回的文件類型直接返回.
-
攔截並返回本地資源
- & 返回本地資源
- & 獲取離線配置 -> 匹配請求地址 -> -> 渲染Web頁面
- & 請求線上資源
-
app針對每個環節出現的錯誤進行上報:
-
離線相關的錯誤類型有:
- 獲取離線配置接口網絡錯誤
- 獲取離線配置接口數據解析失敗
- zip包請求網絡
- zip包解壓錯誤
- zip包md5值app端與前端不一致
- zip包解壓手機空間不足
-
任何一種錯誤都不會更新本地離線資源和離線配置.
一. JSBridge
-
大部分業務需要的native功能
- 視圖層面: 註冊, 登錄, 認證, 註銷組件, 視圖路由
- 存儲層面: 用戶信息, 設備信息, 業務狀態, 緩存
- 網絡層面: 請求header, 代理轉發, 預請求
- app層面: 喚起, 設置, push, 跨app操作
- 系統層面: 底層api的調用
-
其他輔助功能.
-
...其他的不屬於離線包, 暫不處理...
一. 實際應用
- 請求代理
- 預請求
- 統一業務header
- 統一日誌管理
- 跨域
- WebView預創建
二.移動端本地 H5 秒開方案探索與實現》
- 參考: 移動端本地 H5 秒開方案探索與實現
- 適用場景: 需要快速迭代, 客戶端難以實現的, 用作展示的功能模塊, 例如可視化圖表.
二.爲什麼體驗糟糕
-
過程:
-
初始化webview -> 請求頁面 -> 下載數據 -> 解析HTML -> 請求js/css資源 -> dom渲染 -> 解析js執行 -> js請求數據 -> 解析渲染 -> 下載渲染圖片
-
一般頁面在dom渲染後才能展示, 可以發現, H5首屏渲染白屏問題關鍵: 如果減少從請求下載頁面到渲染之間這段時間的耗時.
二.如何優化
-
優化常用方式:
- 降低請求量: 合併資源, 減少HTTP請求數, minify/gzip壓縮, webP, lazyLoad
- 加快請求速度: 預解析DNS, 減少域名數, 並行加載, CDN分發
- 緩存: HTTP協議緩存請求, 離線緩存mainifest, 離線數據緩存localStorage.
- 渲染: js/css優化, 加載順序, 服務端渲染模板直出.
-
直接打包H5相關頁面到客戶端中, 然後客戶端將數據傳遞給頁面, 通過webView加載展示. 不需要網絡請求, webView只要渲染頁面, 執行js即可.
二.實現
-
H5和native通信
- jsapi: 客戶端提供接口, 注入api讓js調用, 直接執行相應的native代碼, 適用於需要通過交互, 進行數據請求的場景
- url scheme: web端發送url scheme請求, 之後native攔截請求並根據url scheme以及所帶參數進行相關操作. 使用頁面跳轉.
- 字符串替換: 客戶端讀取本地H5後, 通過對h5中約定的標記位進行字符串替換. 然後加載展示頁面. 適用於沒有複雜交互, 只通過頁面渲染數據的場景.
-
開發本地H5模塊, 本地模擬數據開發, 然後H5給各客戶端打包後聯調. 繁瑣, 因爲給客戶端打包時比較分散, 不統一, 管理困難.
-
本地h5實現模塊的頁面建議一個統一git倉庫, IOS和android客戶端通過
git submodule
Git Submodule使用完整教程將本地h5的git外鏈到項目中, 客戶端中的資源就可以統一管理了, 解放了每次都手動繁瑣替換打包工作. -
H5資源給到後臺, 客戶端按照業務模塊預下載整個離線包, 離線包根據版本做增量更新.
二.細節
- 預加載webView, 預拉取數據
- 屏蔽webView HTML內容自動識別
- 點擊延遲
- 國際化
- WKWebView兼容
- WKWebView性能相對UIWebView較好. 推薦使用
- WKWebView加載本地的HTML時, 會有兼容問題, 在IOS8不能在HTML文件中引用本地的css或者js或者圖片文件.
- ios8以上是正常的, 可以引用遠程資源.
- ios8使用網絡資源, ios8以上使用本地資源.
- ios8中, 使用遠程cdn的css或者js文件, 引用標籤必須添加charset屬性. 不然css和js亂碼.
三.螞蟻離線包簡介
-
傳統的H5技術容易受到網絡環境影響, 因而降低H5頁面性能. 離線包可以解決該問題, 同時保留H5的優點.
-
離線包是將包括HTML, JavaScript, css等頁面的內置靜態資源打包到一個壓縮包內. 預先下載該離線包到本地, 然後通過客戶端打開, 直接從本地加載離線包.
-
優勢:
- 提升用戶體驗: 通過離線包的方式把頁面內置靜態資源嵌入到應用中併發布, 當用戶第一次開啓應用的時候, 就無需以來網絡環境下載該資源. 而是馬上開始使用.
- 實現動態更新: 在推出新版本或是緊急發佈的時候, 可以把修改的資源放入離線包, 通過更新配置讓應用自動下載更新. 無需通過應用商店審覈, 就讓用戶及時接收更新.
三.離線包結構
- 離線包是一個
.amr
格式的壓縮文件, 後綴.amr
改成.zip
解壓後, 可以看到其中包含了HTML資源和JavaScript代碼等. 待H5容器加載完成後, 這些資源和代碼能在WebView內渲染了.- 一級目錄: 一般資源包的ID, 例如
20150901
- 二級目錄及子目錄: 業務自定義的資源文件. 建議所有前端文件保存在一個統一目錄下.
- 一級目錄: 一般資源包的ID, 例如
* 20150901
* hmpfile.json
* sdk
* www
* index.html
* js
* test.html
* 20150901.tar
* CERT.json
* Manifest.xml
三.離線包類型
- 基礎通用庫使用全局離線包.
- 類型:
- 全局離線包: 包含公共資源, 可供多個應用共同使用
- 私有離線包: 只可以被某個應用單獨使用.
- 使用全局離線包後, 在訪問H5的時候, 都會嘗試在這個包讀取. 如果該離線包裏有對應資源的時候, 直接從該離線包裏讀取, 而不通過網絡. 因此全局離線包的機制主要是爲了解決對於通用庫的使用.
- 由於要保證離線包的客戶端覆蓋率以及足夠的通用性. 此包一般更新週期至少爲一個月, 並嚴格控制離線包大小.
三.渲染過程
-
H5容器發出資源請求時, H5容器或截獲該請求:
- 如果本地有資源可以滿足該請求, H5容器會使用本地資源.
- 如果沒有可以滿足請求的本地資源, H5容器會使用線上資源.
-
無論資源使用線上或者是本地的, WebView都是無感知的.
-
離線包的下載取決於創建離線包時的配置
- 如果"下載時機"配置爲僅WiFi, 只有wifi網絡時纔會下載.
- 如果配置爲"所有網絡都下載", 會消耗用戶流量自動下載, 慎用.
-
如果當前用戶點擊app時, 離線包尚未下載完成, 則會跳轉到fallback地址, 顯示在線頁面.
-
fallback技術用於應對離線包未下載完畢的長江. 每個離線包發佈時, 都會在CDN發佈一個對應的線上版本. 目錄結構和離線包結構一致.
-
fallback地址會隨離線包信息下發到本地. 在離線包未下載完畢的場景下, 客戶端會攔截頁面請求, 轉向CDN地址. 實現在線頁面和離線頁面隨時切換.
三.離線包運行模式
- 請求包信息: 從服務端請求離線包信息, 存儲到本地數據庫過程. 離線包信息包括離線包的下載地址, 離線包版本號等.
- 下載離線包: 把離線包從服務端下載到手機.
- 安裝離線包: 下載目錄, 拷貝到手機安裝目錄.
三.虛擬域名
- 虛擬域名僅對離線應用有效, 當頁面保存在客戶端之後, WebView通過file schema從本地加載訪問的. 然而用戶就能在地址欄裏直接看到file的路徑:
- 用戶體驗問題: 當用戶看到file地址, 會對暴露的地址產生不安全感和不自在.
- 安全性問題: 由於file協議直接帶上本地路徑, 任何用戶都可以看到這個文件所有的路徑, 會存在一定的安全隱患.
- 所以採用虛擬域名的機制. 而不直接使用file路徑訪問. 虛擬路徑是一個符合URL Scheme規範的HTTPS域名地址, 例如:
https://xxxxxx.h5app.example.com
, 虛擬域名的父域名example.com一定得使用自己註冊的域名 - 這個域名可以是網上註冊的, 但是一般情況下, 不建議將虛擬域名配置成互聯網一致的域名, 這個在判斷問題的時候, 容易增加判斷難度, 容易出錯不便於日常管理. 只要保證其父域名
example.com
域名是自己註冊的域名即可. - 標準的虛擬域名如下:
https://{appid}.h5app.example.com
四.螞蟻生成離線包
- 參考: 生成離線包
- 根據不同需求, 將不同業務封裝成爲一個離線包, 通過發佈平臺發佈對客戶端資源進行更新.
- 生成步驟:
- 構建前端.zip包
- 在線成才.amr包
四.構建前端.zip包
- 根據場景不同: 配置路徑分爲:
- 全局資源包
- 普通資源包
- 同一個H5離線包中, 全局資源包於普通資源包不可共存.
- 離線包ID(下文中的一級目錄), 必須爲8位數字.
四.全局資源包
-
可以將被其他多個資源包引用的通用資源放置在全局資源包內, 並按照下列規則指定包內的資源路徑
- 一級目錄: 全局資源包的ID: 如77777777
- 二級目錄: 指向資源可訪問的服務器域名地址.
- 公有云: 固定爲
mcube-prod.oss-cn-hangzhou.aliyuncs.com
(離線包管理->新增離線包頁面的資源包類型中可看到相關提示信息) - 專有云: 請查詢專有云部署的mdsweb服務器域名地址
- 公有云: 固定爲
- 三級目錄: appid_workspaceId, 例如:
53E5279071442_test
- 三級目錄往後即爲業務自定義的公共資源文件. 在公共資源文件的文件夾名, 文件名以及文件中, 避免使用特殊字符. 特殊字符會被urlencode函數轉換字符
-
以上規則組織資源文件後, 即可按照如下格式快速獲取資源文件的路徑:
- 公有云:
http://域名/appid_workspace/資源文件路徑
- 專有云:
http://域名/mcube/appId_workspace/資源文件路徑
- 公有云:
-
示例:
- 在公有云中: 二級目錄固定爲:
mcube-prod.oss-cn-hangzhou-aliyuncs.com
, 所以下圖中資源文件common.js
路徑爲:https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/53E279071442_test/common.js
- 在專有云環境中, 二級目錄爲專有云部署的mdsweb服務器域名地址, 此外
mdsweb-outer.alipay.net
爲例. 下圖資源文件common.js
的路徑爲https://mdsweb-outer.alipay.net/mcube/53E5279071442_test/common.js
- 在公有云中: 二級目錄固定爲:
-
注意實現:
- 公共資源的絕對路徑長度不超過100字符, 否則會導致客戶端加載資源失敗以及頁面白屏
- 服務端未控制全局資源包版本, 用戶可根據實際需求, 通過在三級目錄以後添加文件目錄結構的方式, 來自定義控制文件的高低版本.
- 在專有云環境中, 如果服務端採用的文件存儲格式爲HDFS或AFS, 則需要在上述第三級目錄前增加一個目錄, 該目錄名稱爲mdsweb目錄, 該目錄名稱爲mdsweb服務器中的存儲空間(bucket)的名稱.
- 引用公關資源: 在普通離線包內訪問全局資源包中的內容, 必須通過絕對路徑訪問, 如:
https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/53E5279071442_test/common.js
四.普通資源包
-
按照業務將相關的HTML, CSS, JavaScript, 圖片等前端資源放置在同一個離線包內, 目錄結構如下:
-
一級目錄 普通資源包的ID, 如20171228.
-
二級目錄及往後即爲業務自定義的資源文件. 建議在所有的前端文件最好保存一個統一的目錄下, 如
/www
, 並設定當前離線包默認打開的主入口文件, 如:/www/index.html
-
.
-
配置萬資源包的路徑後, 即可直接將appid所在的目錄整體壓縮爲一個.zip包.
四.在線生成.amr包
- 進入控制檯的
實時發佈->離線包管理
頁面,.zip
包上傳到MDS發佈平臺, 生成.amr
包.
五.H5秒開方案大全
五.常用的加速方法
-
資源加載:
- 針對首屏
- 更小的資源包
- 壓縮, 減包, 拆包, 動態加載包, 圖片優化
-
html渲染:
- 針對可優化
- 更快的展示內容
- cdn分發, dns解析, http緩存, 數據預請求, 直出
-
rn, weex, flutter衝擊傳統hybrid, hybrid加速發展.
五.直出+離線包緩存
- 直出: 後端渲染, 省去了ajax請求時間, 能夠通過各種緩存策略優化很好, 加載html扔需要時間.
- 離線包技術: 解決html本身加載需要的時間問題.
- 離線包基本思路通過通過webview統一攔截url, 將資源映射到本地離線包, 更新的時候對版本資源檢測, 下載和維護本地緩存目錄中的資源.
- 對於web端而言: 相對透明, 侵入性比較小.
五.客戶端代理的VasSonic 騰訊手 Q VasSonic 秒開
-
用戶點擊到看到頁面之間, 存在webview初始化, 請求資源的時間, 這裏的過程是串行的, 所有存在優化空間.
-
支持離線包策略, 並更進一步
- webview初始化和通過客戶端代理資源請求並行
- 流式攔截請求, 邊加載邊渲染
- 實現了動態緩存和增量更新
-
客戶端代理請求並行:
- 創建webview之前, 通過客戶端代理建立網絡鏈接, 請求html, 然後緩存起來.
- 等待webview線程發起請求html資源的時候,客戶端攔截, 將緩存的html返回給webview
-
動態緩存和增量更新:
- 自定義了一套標籤. 將html區分爲模板和動態數據兩部分.
- 拓展了http頭部, 定製了一套請求後臺的約定
- webview發情請求的時, 會將頁面內容的id攜帶過去, 後臺判斷後, 再告訴客戶端是否更新局部數據
- 如果是緩存額html模板和新數據拼接成新的html, 最後計算差異部分, 通過js回調給頁面, 進行局部刷新
-
通過模板可以達到局部變化, h5秒開結果.
-
但定義了一套特殊的註釋標記及拓展了頭部, 需要包括後臺在內的前後端進行改造. 對web入侵性非常強. 維護成本高.
五.PWA+直出+預加載
- 不管是離線包技術, 還是webview代理請求, 都對前端入侵比較大.
- pwa能夠通過純web的方案優化加載性能.
- 對於直出html, 配合pwa, 直出文件, 緩存到cacheStorage, 在下一次請求時, 優先從本地緩存中讀取, 同時發起網絡請求更新本地html文件.
- 第一次加載通過app預加載一個js腳本, 拉去需要pwa緩存的頁面, 可以提前完成緩存.
- 非直出頁面.
- 第一次只能提前加載. 預加載腳本.
- 第二次非直出頁面, 每個頁面需要有獨一無二的標記, 比如hash. 瀏覽器獲取到數據, 渲染好的html, 通過outerHtml方法, 將html緩存到cacheStorage中.
- 第二次優先從本地獲取, 同時發起html請求, 通過對比其中唯一標識的差距, 決定是否需要更新.
- pwa一系列方案替代離線包, 屬於web標準, 適用於普通能夠支持service-worker的H5頁面.
- 在兼容問題允許的情況下, 建議主加.
五.NSR渲染
- 前端SSR
- 借住瀏覽器啓用一個JS-Runtime, 提前將下載好的html模板及預取的feed流數據進行渲染. 然後將html設置到內存級別的MemoryCache中, 從而點開即看.
- NSR將SSR渲染過程分發到各個用戶的端. 減少後臺請求壓力, 進一步提高頁面打開速度.
- 數據預取和預渲染帶來的額外流量和性能開銷, 特別是流量. 如何更準確的預測用戶行爲, 提高命中率非常重要.
五.客戶端PWA
- service-worker在webview實現性能並沒有想象中好.
五.小程序化
- 小程序內部將webview渲染和js執行分離開, 然後通過離線包, 頁面拆分, 預加載頁面等手段
- 犧牲了web的靈活性.
- 對於hybrid開發, 通過原生客戶端底層支持小程序環境, 大量業務邏輯採用小程序方案開發
- 迭代速度和性能兼容, 是一個不錯方向
五.總結
- 在整個鏈路中減少中間環境, 例如串行改並行, 包括小程序內部執行機制.
- 儘可能預加載, 預執行. 比如從數據拉去, 到頁面渲染.
- 任何轉換都有代價, 加速本質上就是在用更多的網絡, 內存和CPU換取速度. 以時間換空間
六.轉轉hybrid app web靜態資源離線系統
六.前言
-
優點:
- web頁面上線滿足快速迭代的業務需求, 不收客戶端審覈和發版的時間限制.
- 也可以將各個業務線的開發工作分攤到各個業務的fe團隊上, 是的業務線並行開發.
-
缺點:
- web應用的性能和體驗, 不及客戶端.
-
痛點1:
-
打包後靜態資源過大, 首次打開/線上H5資源更新/網絡條件差/本地頁面緩存失效.
-
白屏.
-
痛點2:
-
app使用系統原生的web view, 不兼容pwa.
-
各個業務團隊使用的技術棧比較廣. 各個業務線快節奏開發, 需要低成本接入. 對業務代碼不會產生入侵.
六.方案
-
前端構建發佈:
ak-webpack-plugin
: 根據配置, 將webpack的構建出的靜態資源, 壓縮成了靜態資源在cdn路徑url的zip包, 同時在配置的過程中, 可以選擇排除掉部分文件.(例如, 部分圖片)- 不需要關注資源之間的依賴關係, 更不需要關注具體的業務邏輯.
- 只需要關注webpack構建後生成的資源文件夾的結構.
- 使用jenkins.持續集成和發佈.
-
app:
- 預置一份最新的各個業務線的離線包與版本號的配置表.
- app啓動時, 會將壓縮包解壓到手機rom中, 各業務線配置中包含app訪問線上的靜態資源時需攔截的url規則map:
- 當app訪問到與規則map相匹配的地址時, 就轉爲本地資源, 達到離線訪問目的.
[{
"bizid": 13,
"date": "1513681326579",
"ver": "20171219185710",
"offlinePath": [
"c.58cdn.com.cn/youpin/activities"
]
}]
-
離線資源如何更新
- 客戶端啓動後, 向離線系統查詢最新的各個業務的離線包版本號, 依次跟本地配置中的對應業務線比較.
- 如果需要更新, 則再次向離線系統查詢此業務線的離線包信息. 離線系統會提供此業務線的離線包的信息.
- 判斷是否需要更新:
- 線上的各業務線的離線包版本號與本地配置中 同一業務線的配置不同(不論最新的離線包版本比本地更高或者更低)
- 線上的各業務線的配置中包含本地配置沒有配置的業務線.
六.離線包加載優化
- 增量的資源更新 (bsdiff/bspatch)
- 影響bsdiff生成的差分包的體積因素主要有:
- zip包的壓縮等級
- zip包中文件內容的修改. 比如js進行了uglify壓縮, 變量名的變化可能引起大幅的變更.
- 可以減少客戶端升級離線資源需要下載的流量
- 影響bsdiff生成的差分包的體積因素主要有:
- 單獨控制各個業務線web應用是否使用離線機制
- 每個業務都加入使用離線資源的開關和灰度放量的控制.
- 數據一致性校驗 與 數據安全性校驗.
- 防止下載離線資源在傳輸中被篡改, 使用md5驗證.
- 同時保證傳輸過程中, 資源文件不被篡改, 將md5值通過rsa加密算法進行加密, 在服務端和客戶端分別使用一對非對稱的密鑰進行加解密.
- 批量下載:
- 啓動app後, app會集中批量下載各個業務線的離線包資源, 在cdn中使用http2協議, 一次鏈接, 下載所有資源. 離線包個數較多的情況下, 可以比傳統http1有更快的傳輸速度, 同時, 客戶端只需要運行一次下載器. 減少多次運行下載對手機cpu損耗.
六.回退機制 fallback
- 可能出現的問題:
- 本地內置的base包(zip文件)解壓失敗
- 離線系統接口超時
- 下載離線資源失敗
- 增量的資源合併失敗等情況
六.離線資源管理平臺
-
功能:
- 查看和管理各個業務線信息及其離線功能的灰度放量比例.
- 通過業務線, 版本號, 發佈時間等條件. 查詢各個版本的離線包資源列表及其詳細信息
- 針對全局離線功能, 提供了離線功能開關.
- 允許將某個版本的離線包下線, 以實現離線資源版本的回滾功能.
六. 技術選型
- 離線系統的服務端使用nodejs實現.
- 使用輕量的koa框架.
- 使用log4j進行node日誌的採集和記錄.
- 使用輕量的nosql數據庫mongdb記錄離線包的數據信息. 使用對象模型工具mongoose進行nosql操作
- md5的加密, 使用node-rsa庫進行非對稱密鑰的生產, 操作和加密解密處理.
- 前端離線系統的後臺頁面, 使用vue與組件庫iview.
- 壓力測試: 使用壓力測試工具siege.
- 建立性能監控系統, 運行穩定性/承載的壓力/佔用服務器硬件資源情況.
六.運行情況
- cpu使用率
- 應用內存使用量
- 頁面靜態資源加載(js, css)耗時
- 頁面可操作時間耗時
六.展望
- 下載引擎優化
- 斷點續傳/分塊下載
- 離線資源的統計
- node api層/cdn的nginx層實施
- pwa技術
- 通過接入其他更強大的瀏覽器內核實施
七.今日頭條品質優化:圖文詳情頁秒開實踐
七.數據建立
-
頁面加載時間 = 頁面加載完成時間 - 頁面開始加載時間
-
頁面開始加載時間: 點擊了Feed上的卡片.
-
loadFinish回調不能反映用戶的真是體驗.
-
WebView渲染步驟:
- 解析HTML文件
- 記載JS和css文件
- 解析並執行js
- 構建DOM結構
- 加載圖片等資源
- 頁面加載完成
-
用戶真實角度: dom結構構建完成(domReady)的時間點作爲頁面加載完成
七.白屏
- 對webview進行截圖, 遍歷截圖的像素點的顏色值.
- ios提供了webview快照的接口獲取當前webview渲染的內容, 底層異步回調, api耗時10ms.
- android中提供獲取視圖內容結構爲
getDrawingCache
, api耗時40ms - webview截圖的圖片進行縮小到原圖1/6, 遍歷檢測圖片的像素點, 非白色像素點大於5%的時候, 認爲非白屏情況, 可以相對高效檢測準確得出詳情頁是否發生了白屏
七.指標建立
-
明確問題: 什麼指標可以反映用戶刷頭條時的真實體驗
-
最開始: 頁面平均加載時長: 頁面加載時長總和 / 頁面pv
-
平均加載時長雖然可以反映詳情頁加載速度, 但因爲詳情頁的pv比較高. 如果使用平均加載數度, 很多用戶體驗問題, 都被忽略掉了. 並不能反映用戶的真實情況.
-
調整口徑: 所有用戶進入詳情頁的80分位值
-
80分爲值是1s, 說明80%用戶進入詳情頁都能在1s內加載完成.
-
優化目標爲 80%用戶, 0.3s加載完成.
-
後來提高到95分位
七.模板優化
-
模塊拆分:
-
點擊後的過程:
-
線上頁面加載用戶每次進入詳情頁都要多次網絡加載, 極容易受到網絡波動影響, 無法保證頁面加載的時長和成功率, 極大的影響用戶體驗.
-
於是, 在頭條中, 我們將新聞中標題和正文內容分開, 把頭條詳情頁的公共樣式css和邏輯js都抽離出來, 形成一個獨立而完備的詳情頁模板, 可以把模板內置到客戶端中(這不就是離線包嗎.)
-
同時和前端約定好js腳本, 通過接口將正文內容數據注入頁面完成詳情頁的頁面展示, 通過這種方式可以將接口放到客戶端上請求.
-
客戶端通過一定策略預加載新聞數據, 在理想狀態下用戶進入頁面看到頁面時,就可以直接使用緩存的數據. 用戶在看新聞的時候可以完全實現離線化, 避免受到網絡的影響.
-
模板預熱:
-
全流程離線化之後, 頁面加載的瓶頸變成本地模板加載, 優化本地模板加載.
- 模板合併: 加載完html再去加載js和css, 需要多次io操作, 於是把js和css還有一些圖片都內聯到一個文件中, 加載模板就只需要一次io操作.
- 模板簡化: 將非必須的腳本異步拉取, 精簡不必要的樣式和JS代碼, 將模板大小壓縮了20%以上.
-
模板和數據分離後, 用戶點擊的時候加載的是同一個模板, 實際上, 我們並不需要在用戶進入頁面的時候去創建webview以及加載模板
-
只需要在合適的時機在後臺創建webview, 並且提前預熱模板.
-
用戶進入頁面的時候, 就能使用已經加載好模板的webview, 直接將詳情頁的內容數據通過js注入到頁面中. 前端收到數據, 渲染即可.
-
模板複用:
-
95分位看實際數據優化並不明顯, 從數據上觀察, 用戶預熱模板的命中率只有53%, 可進一步提升.
-
爲了儘可能提高頁面加載速度, 我們希望用戶每次進入詳情頁都能夠使用預熱好的webview, 模板預創建池手段優化用戶進入詳情頁時的預熱模板命中率.
-
webview的創建是一個性能開銷比較大的操作, 使用雨創建池的方案, 就會在後臺頻繁創建webview, 這樣對用戶在feed場景的瀏覽提體驗也會有一定影響.
-
每次使用同一個模板, 用戶退出頁面後, 把正文數據清空, 進入下一個頁面的時候能夠繼續複用這個webview, 重新注入數據即可
-
避免了後臺創建webview對用戶刷新feed體驗, 又提高了預熱模板命中率.
七.網絡優化
- CDN加速
- 容災
七.渲染優化
-
服務器端預渲染:
- 服務器端把所有的詳情頁正文的HTML數據組裝好, 通過將服務端直出內容注入到頁面中. 直接給webview渲染.
-
客戶端渲染:
- webview渲染非文字部分存在一下問題:
- 渲染效率差
- 大量圖片, webview的渲染內容佔用, 滑動體驗
- 多次打開同一篇文章, 多次加載問題, 無法與客戶端進行緩存共享.
- 圖片和視頻等非文字內容通過原生組件放在客戶端進行渲染, 提高渲染效率, 減少流量
- 多圖文章, feed頁面, 只能加載詳情頁需要的圖片, 增加用戶的文章首屏體現.
-
白屏優化
- ios中, 我們使用系統自帶的WKWebView, 一個運行在獨立進程中的組件, 所以, 內存過大的時候, WKWebView所在的WebContentProcess會被系統kill掉, 反映出來就是白屏
- 根據WKWebView提供的回調
webViewWebContentProcessDidTermainate
函數進行reload重新加載. 因爲是模板, 沒有辦法注入數據. - 嘗試重新注入時間很長. 在注入腳本中判斷是否存在數據注入接口, 如果不存在, 直接重試.
- android, 使用自研內核webview
- 多線程讀模板問題, webview在運行中會讀取的文件模板, 此時如果另一個線程同時更新模板文件, 就出現了模板加載問題, 需要保證模板加載的原子性.
- Render卡死問題, 內部渲染可能會出現Render卡死問題. 從業務上做白屏監控進行重試.
-
不管是IOS和Android, WebView加載邏輯都比較複雜, 重試頁無法成功時, 會降級加載線上的詳情頁, 優先保證用戶的體驗.
七.總結
- 數據很重要: 優化加載之前第一件事, 就是建立一個詳情頁的數據看板, 只有通過數據, 我們才能瞭解目前線上用戶的現狀, 從真實用戶的體驗找到瓶頸和優化點.
- 用戶體驗優先: 優化方案很多, 除了加載速度之外, 需要從整體應用體驗出發, 選擇對用戶最佳的方案
- 追求極致: 扣細節, 到極致.