無線webapp安裝更新機制

摘要 

爲了滿足移動終端:節省流量、減少請求、提高客戶端性能的需求,我們設計了webapp安裝更新程序,把js、css、html和圖片這些資源,序列化爲字符串存入客戶端本地存儲,並帶上版本號來實現資源細粒度更新。

TAG

webapp 安裝啓動 性能優化

1、概述

我們認爲webapp是一站式的應用,在一個頁面裏能完成整站的功能。所以,以前通過頁面全刷的跳轉,現在變成了通過底層框架來支持的局刷和切換動畫。爲了支持這些功能,會多出不少的代碼,再加上app裏的功能代碼,我們統稱爲資源,包括底層庫js(zepto、iscroll、baiduTemplate等),通用ui組件和app功能性的js、css、html和圖片。

如何處理一個頁面裏的這麼多資源,才能降低對性能的影響呢?爲此,我們設計了webapp安裝更新程序,可以做到減少資源請求,節省流量,提升客戶端性能。

 

2、瀏覽器緩存方案

使用瀏覽器對資源緩存,這是通常的做法,能快速加載頁面,只需設置資源一個較長的過期時間即可,當服務器端資源有更新時,改變資源路徑就能使客戶端及時獲取更新。

但缺點是,在webapp應用場景中,有大量的資源需要被下載,資源請求數可能過多,目前正在開發的貼吧webapp宙斯版,已經有60個請求了,預計會過百,當然我們可以把資源文件合併,但又帶來了另外一個問題,下載粒度較大。當更新了一個較小部分,會導致大粒度資源被重新下載。由於手機硬件和手機網絡的限制,每多一個連接請求的時間消耗和資源下載導致的流量耗費,都是無線webapp要考慮的重要因素。

另外一個缺點就是隻能緩存文件,不能緩存一些常量,比如前端模板html片段。

爲此,我們設計的webapp安裝更新程序,能夠只在一個請求中下載所有資源文件內容。當資源有更新的時候,也是在一個請求中只獲取有更新的小粒度文件,並且能在客戶端緩存常量,如html片段等。

3、自定義安裝更新程序

我們想把資源細粒度的存儲在客戶端,當資源有更新的時候,客戶端能及時同步更新。要解決兩個主要問題:1、如何在客戶端存儲資源;2、如何及時獲取更新通知,並執行資源更新。

1)      客戶端資源存儲

我們把資源序列化爲字符串,以鍵值對的方式存入客戶端本地存儲(localstorage)。比如基礎庫zepto.js文件,在本地存儲中的key爲zglobal/js/base/zepto.js,value就是zepto.js的被壓縮後的字符串內容了。同理,css文件,html前端模板都是一樣,適合做成base64編碼的圖片會以base64字符串的形式存在css文件。

在資源被引用的地方,如果是js文件,我們會從本地存儲中取出js字符串內容,執行eval函數;如果是css文件,我們會動態創建style元素,包含css內容,追加到HTMLDocument的head部分;如果是html前端模板,就在用到的地方,從本地存儲獲取前端模板字符串,然後調用模板方法進行渲染。

資源本地存儲示例片段:

圖一

資源的引用方式sample code:

圖二

2)      獲取資源更新通知

實現資源更新要依賴於資源版本號。我們把每個資源緩存項都對應一個版本號(文件的md5值的前8位),整站所有資源緩存項對應一個總的版本號(所有資源緩存項的版本號的md5值)。

具體流程是:我們把總版本號存入cookie,在一些入口url的服務器處理程序中,判斷客戶端cookie是否和當前服務器資源總版本號是否相同,如果相同,則跳過資源更新處理,直接啓動app,如果不同,說明有資源更新,此時,客戶端發送一個ajax請求,帶上當前客戶端每個緩存項的版本號,向服務器獲取更新項,服務器對比客戶端每個緩存項的版本號,就知道客戶端哪些資源是需要更新的,哪些資源是被刪除了的,因此,服務端就能只返回被更新了的資源。那麼,客戶端是如何拿到當前客戶端每個緩存項的版本號呢?其實是依賴於服務器響應客戶端ajax資源更新請求時,會包含每個更新了的資源緩存項的名稱、版本號和資源內容字符串,客戶端拿到這個結果,會更新本地存儲中專門用來記錄更新後每個資源項的版本號的一個本地存儲項,以一個json對象序列化後的字符串形式存在,因此客戶端發送的ajax請求,就是直接帶上這個json字符串即可。

程序流程:

圖三

圖三中的totalItemVersions就是所有細粒度資源緩存項的版本號記錄。在客戶端本地存儲中的key爲totalItemVersions,value是{“zglobal/html/frsMostTemplate.html”:”d6670285″,”zglobal/js/base/ajaxStore.js”:”68ce034f”,”zglobal/js/base/appBaseController.js”:”4083dd27″,”zglobal/js/base/appBaseModel.js”:”f1f806f1″,”zglobal/css/common/app.css”:”66153242″,”zglobal/css/common/base.css”:”2731733d”……….}

通過以上,我們能發現,當服務器端無資源更新時,啓動的webapp將不會有網絡資源請求,直接加載本地資源,然後啓動app,後續只是app動態的json數據交互;當服務器有資源更新時,不管被更新的資源的多少,客戶端都是通過一個請求獲取僅更新的資源,然後加載資源,並啓動app。

4、本地build

瞭解了前面整個客戶端和服務器的交互之後,我們可能會關心,這些資源在服務器端是如何生成並存儲的?這依賴於一個本地build過程。

在貼吧的前端開發中,是按不同模塊來開發的,不同模塊包含不同的功能,這樣能減少大家同時修改帶來的衝突。最後的上線,也是按修改的哪些模塊,只上線相應的模塊修改即可。

每個模塊下都會有本地build腳本,只負責本模塊的build工作。對於安裝更新這塊來講,本地build輸出兩個文件,moduleVersion.php和cache.php。

cache.php就是當前模塊下所有的資源緩存項,每個項的version就是資源文件的md5值的前8位,cache.php文件如下:

圖四

moduleVersion.php表示當前模塊的版本號,文件如下:

 

圖五

模塊版本號的計算方法是當前模塊下所有緩存項的版本號的總連接字符串的md5的前八位。這樣當任何一個資源文件有修改的話,資源文件的version將會改變,moduleVersion的值也會改變。

在“獲取資源更新通知”一節中,提到了整站所有資源緩存項的總版本號,這個版本號的計算方法是,所有模塊的版本號的總的連接字符串的md5。

圖六

5、使用建議

如果大家也在做無線webapp,建議不妨試試這種資源處理方式,將會有更少的資源請求,並且讓資源更快加載,給用戶帶來更好的體驗。

by gaofei

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章