頁面緩存小結

要打開一個頁面,總會牽扯到很多資源,其中包括但不局限于以下這些內容:

頁面本身,頁面包含的自頁面(比如通過frame,iframe,等等);

CSS與JS等腳本(如果你安裝了Mathematica,那么你還可以調用這貨的網頁腳本來執行各種命令。此外還有古老的VBS甚至WSHost的Shell);

各種圖片等資源文件;

其它(這句好廢哦……)

因此,打開一個頁面,不單單是打開一個頁面,而是需要再如很多東西。

下面就來說以下關于頁面緩存的事。


頁面緩存是干嘛的?

說到這個,就要先說一個瀏覽器的基本機制。

以Webkit為例(我也只熟Webkit。。。)

Webkit有一個Resource模塊,用來管理各種資源的加載與使用——如果你有幸看過圖形圖像引擎gdx的話,你會發現它也有一個Resource模塊,干的是相同的事情,不過針對的是OpenGL/OpenGLES罷了(所以還會緩存shader文件)。

這個模塊的基本邏輯是這樣的:

你問我要一個資源,如果沒有,就按照URL去請求;如果有,就詢問是否過期(內存中是否過期以及資源本身是否過期),如果過期,就按照URL請求,如果沒過期,就直接返回這個對象。

因為有這個模塊,所以如果你在一個網頁里同時需要現實多張一樣的圖片,它們不會被從服務器請求多次,而是只請求一次,然后所有需要顯示圖片的Webview組件同時加載這同一份資源。

所以,在網速較慢的時候,你會發現這多張圖片是被同時從上到下刷新的;如果加載的是GIF,那么這些GIF也是按照同一個起點在播放的(這里牽扯到了一些和EventLoop以及GIF的GetFrame相關的機制,所以略有不同,這里不說了)。

這里重要的就是:瀏覽器對資源是有做緩存的,只不過會檢測資源是否過期,僅此而已。

嚴格說來,上面的說法還不完全對。

比如,如果是內存中資源過期,那么瀏覽器并不是直接從URL請求,而是會先從本地緩存讀取,同時判斷本地緩存是否過期——這就是所謂的資源本身是否過期。

也就是說,如果一份資源在本地緩存中存在,且沒有過期,那么是不會從URL指定位置重新要數據的。

這就是資源的Head中的Expire的作用——它告訴瀏覽器這份資源多久過期。當然,也可以通過發別的Head讓資源立刻過期。

老式互聯網時代的老式網站里經常會看到很多資源的Expire很長很長,于是你會郁悶地發現訪問一個網站結果看到的還是老的圖片,這個很郁悶。老式網站的一般解決方案是:把資源換個名字。。。。。。瀏覽器里會保留老的資源直到過期,同時還有一份新的資源,所以IE的本地緩存往往十分巨大,Windows優化大師的一般瘦身攻略就是干掉IE緩存。。。

到這里,我們已經接觸到了第一類頁面緩存機制:Cache-Expire機制。

現代瀏覽器當然不僅僅有這種古老的機制,還有很多別的方案。

比如,HTML5中可以用來緩存的方案就很多,比如:

Application Cache,LocalStorage,FileSystem,WebDB,IndexDB,等等。


Application Cache是一個很牛叉的東西,它通過一份配置文檔告訴瀏覽器哪些資源是直接保存在本地的,這個意思就是說:這份資源就在你的電腦上,訪問的時候也是直接從你電腦上訪問,而不需要在問瀏覽器。

和傳統的Cache-Expire機制的不同就在于檢測是否過期這件事上。

如果資源的過期時間很長,那么一旦網站有更新,你就無法即使更新圖片,會有問題。而且這種機制對頁面無效。另一方面,如果Expire很短,那么緩存十張圖片,那么在你再次打開頁面的時候,會發送十次資源請求,服務器回答沒有更新可以拿老的資源(304信號),然后你才可以繼續拿老的最遠而不是請求新的資源,換言之存在一個詢問是否過期的過程,十張圖片就是十次,不是很節約。尤其網絡環境不好的時候,就會導致加載速度變慢。

Application Cache就不同了,一個頁面的所有資源是否過期完全由配置文檔是否過期來決定,如果配置文檔沒有過期,那么整個頁面的資源都不需要重拿;如果配置文檔過期,那么再按照正常的Expire-Cache流程走——換言之,在不需要更新的時候,Application Cache只需要確認一次過期,而傳統的是有多少資源確認多少自,浪費Http鏈接;而在緩存已經過期的時候,則和傳統方案一致。

更重要的是,Application Cache由于上述機制真正做到了離線瀏覽——雖然傳統的老的瀏覽器早就只是了離線模式,但還是需要用戶自己來開啟,Application Cache則是全自動的。


但Application Cache有一個問題,拿就是它是以文件為單位的,而且是由服務器決定的。如果是一些運行到一般的中間變量,那AC就無效了。

這個時候你需要LocalStorage。

LocalStorage將數據以Key-Value這種橙須猿很熟悉的形式保存在瀏覽器的本地緩存中,從而不會因為網頁的關閉而消失。

而且,它不是以文件為單位,而是以變量為單位,這就很靈活了。

當我們作一個大型網站,或者一個WebApp(比如游戲)的時候,就會大量使用LocalStorage來保存一些用戶設定或者游戲進度等信息。

基本上,如果一份信息不需要和別人交互,服務器也并不真的非要不可,那么就可以保存在本地——這就是LocalStorage的功能。

比如說,簡書的黑夜/白天設置,這個其實完全可以保存在LocalStorage中——但如果用戶都要求說我從不同的設備登錄這個網站都要拿到相同的設定,拿就還是需要保存在服務器的(當然,就個人來看,這種要求可以忽略……)。

使用LocalStorage可以將這些無關的設定保存在客戶端,從而節約服務器端數據庫空間(雖然估計很有限),需要的時候從客戶端拿嘛。

LocalStorage的胞弟SessionStorage也可以用來保存數據,不過這種數據一般就是單窗口有效的。SessionStorage的數據只在打開頁面的窗體內始終保存,但和頁面級的保存不同,你跳轉頁面后這些數據還在,直到你關閉這個窗口位置。

LocalStorage還提供update事件,從而可以做到一個網站的多個窗口之間的數據同步和通訊,這個對IM或者游戲來說很重要。

LocalStorage的一個限制是,不同的瀏覽器有不同的空間上限,比如Chrome是5MB,一般來說也是夠用了。


比如LocalStorage更專業的就是WebDB了,以數據庫的格式在本地維護數據,做游戲必備,這里不多解釋。


Local Storage用來保存零散的變量,Application Cache則只能以配置好的文件為單位緩存文件,不夠靈活。

這種的方案,就是超級重量級的大殺器:FileSystem。

FileSystem讓網站設計者有權限在瀏覽器于用戶本地的可用空間范圍任意讀寫文件。

這就非常靈活了,不受Application Cache的配置限制,也不像Local Storage有格式和容量限制。

這貨要怎么用,就完全看網站設計者高興了。


下面來說一下比較常見的綜合型緩存機制。


首先,傳統的Expire-Cache機制肯定還在。

然后,就是網站的最穩定的部分,比如HTML框架,核心JS與CSS,這些都用ApplicationCache做緩存,基本都是半年一年甚至再也不會更改的,很穩定。

社交類網站除了上述框架外,最經常變動的,就是文章帖子內容,以及,各種圖片聲音等資源。

上述資源又可以分為幾類——

有些是“一次性消費”,比如今天看了一篇文章,上面出現了某個用戶的頭像,但以后我再也不看了。

所有訪問次數很少的(基本三次一下就可以認為很少),都屬于一次性消費,這類東西沒必要做緩存,不值當。

有些是“長期消費”,比如我關注的用戶中最活躍的幾個,他們的文章我常看,于是它們的頭像對我來說就是長期消費——不但是頭像這個圖片資源,也包括它們的個人數據中穩定不變的部分,比如個人簡介。這種資源一個兩個人也就算了,人數一多,也就很可觀了。還比如某些類型的網站會出現一些文章一個用戶會長期經常反復訪問(比如李毅吧置頂帖)。

還有一些是“穩定消費”,比如一個論壇的主題(包括一組CSS、JS和圖片),基本我選定以后一長段時間里不會變。它們尷尬的地方是——相比框架性資源,它們沒那么恒常;相對長期消費資源,它們又足夠穩定。所以這類東西的緩存就要使用不同的方案。

對于穩定消費資源,就可以使用FileSystem寫到本地,當用戶換主題的時候就刪除久主題,重寫新主題。一套主題資源寫到FS里,以后的開銷都問FS拿,不需要再問服務器要,節約了流量和加載時間。

而長期消費中非圖片聲音等大型資源外,內容數據就可以用LocalStorage來做緩存處理——就算只有5MB對純文本來說也足夠了,當然你別跟我提什么你叔叔純TXT的黃書有10GB這種奇葩案例……長期消費中的大型資源可以考慮用FileSystem做緩存。

當然,對于JS文件和CSS文件,可以使用FS緩存,也可以寫入LS中(使用的是偶從LS中讀取然后寫入Script或者Style標簽動態加載到頁面中即可)。

用戶個性化設置也可以用LocalStorage,最多就是每次有修改了告訴服務器,第一次瀏覽的時候拿一遍,而不需要每次都從服務器端拿一遍。

一次性消費,無視掉吧。


因此,我們完全可以創建一個Resource的JS模塊來完成這件事。

它的作用就是根據請求資源ID來查看LS或者FS,如果有就返回本地緩存數據(如果是圖片的URL就返回FS的URL),如果沒有再問服務器要。然后可以開一個服務器接口是詢問最新資源的TimeStamp,供瀏覽器去確認。

Resource模塊的另一個作用,就是根據對資源的訪問頻次來決定什么資源使用什么類型的緩存,這是一個純配置和計數,就不說了。


當然,上面是基本思路,實際構建模塊的時候肯定還會有別的問題,這里就姑且忽略掉吧~~~(這句話好不負責任啊…………)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • 轉載:H5緩存機制淺析-移動端Web加載性能優化【干貨】 作者:賀輝超,騰訊游戲平臺與社區產品部 高級工程師 目錄...
    meng_philip123閱讀 11,543評論 6 48
  • 0. 前言 前面有被用戶投訴 APP 流量消耗厲害: 于是乎考慮了流量方面的問題。暫時 APP 中涉及流量的幾個方...
    zyl06閱讀 24,173評論 5 63
  • 一、前言 工作上遇到一個這樣的需求,一個H5頁面在APP端,如果勾選已讀狀態,則下次打開該鏈接,會跳過此頁面。用到...
    eraser123閱讀 1,021評論 2 47
  • 一:在制作一個Web應用或Web站點的過程中,你是如何考慮他的UI、安全性、高性能、SEO、可維護性以及技術因素的...
    Arno_z閱讀 1,204評論 0 1