我理解的瀏覽器緩存策略

瀏覽器資源緩存策略

瀏覽器的緩存大體分爲四個方面html

  • Memory Cache(disk Cache)
  • Service Worker Cache
  • HTTP Cache
  • Push Cache

HTTP Cache

  • 瀏覽器在請求資源前會優先檢測本地是否有命中強緩存。
  • 強緩存分expires與Cache-Control兩種。
  • 若是命中強緩存則會向 memory cache或disk cache等多種緩存中去獲取。
  • 若是沒有命中則會向服務端去請求資源。 HTTP緩存分爲強緩存與協商緩存強緩存使用expires與Cache-Control等屬性來控制

強緩存

expires

expires是HTTP/1.0時期提出的,主要是由服務端設置過時時間,而後瀏覽器經過對比本地時間與expires來肯定資源是否過時是否是須要向服務端去索取資源。前端

expires: Wed, 11 Sep 2019 16:12:18 GMT

複製代碼

缺點: expires是經過瀏覽器本地時間來對比的,若是人爲的修改本地時間會致使資源緩存強緩存命中失敗,從新去獲取資源git

Cache-Control

Cache-Control是HTTP/1.1做爲expires全面的代替者提出的,經過對Cache-Control設置不一樣屬性來進行資源緩存的斷定github

其屬性值有瀏覽器

  • no-cache: 數據內容不能被瀏覽器緩存, 每次請求都從新訪問服務器確認是否過時(進行協商緩存), 如有max-age, 則緩存期間不訪問服務器.
  • no-store: 瀏覽器、服務器、代理服務器等所有不能緩存,
  • private(默認): 只能在瀏覽器中緩存, 只有在第一次請求的時候才訪問服務器, 如有max-age, 則緩存期間不訪問服務器.
  • public: 能夠被任何緩存區緩存, 如: 瀏覽器、服務器、代理服務器等
  • max-age: 相對過時時間, 即以秒爲單位的緩存時間.
  • s-max-age: 與max-age類似,二者同時存在時優先使用s-max-age,並只在代理服務器使用且只對public有效
  • no-cache, private: 打開新窗口時候從新訪問服務器 , 若設置max-age, 則緩存期間不訪問服務器.
  • private, 正數的max-age: 後退時候不會訪問服務器
  • no-cache, 正數的max-age: 後退時會訪問服務器
cache-control: max-age=3600, s-maxage=31536000
複製代碼

若是隻設置了max-age,默認會採起public模式模式能夠被全緩存的緩存

協商緩存

協商緩存是瀏覽器與服務器之間的通信,瀏覽器向服務器詢問相關信息,肯定本地文件是否過時是否須要向服務器從新獲取資源,若是資源沒有變更則會重定向至瀏覽器端而且此時的Status Code爲304 Not Modified性能優化

那麼協商緩存緩存是怎麼實現的呢?

  • 經過Last-Modified與ETag來進行

Last-Modified

當cache-control爲no-cahce時在響應頭上會帶上Last-ModifiedETag,同時Last-Modified是一個時間戳。bash

而且瀏覽器會在隨後的請求的請求頭上都攜帶上 If-Modified-Since,這個If-Modified-Since也是一個時間戳,而這個 If-Modified-Sincee也正是上次請求的資源中攜帶過來的 Last-Modified,這個時候服務器會對比該資源的時間戳跟服務器上的資源的時間戳是否同樣,若是一致則返回304,重定向讓瀏覽器在緩存中取得,若是不一致則從新返回文件。

可是一樣這樣也是有弊端的

  • 若是修改了文件可是沒有修改內容,這樣文件的修改時間一樣會發生變化,一樣觸發校驗時則會致使觸發一次資源的從新請求
  • 由於Last-Modified與If-Modified-Since都是使用時間戳來設置的,只要修改保存的時間足夠快在100ms內完成了改動,則時間戳並不會變化,使得在校驗時沒法檢驗出變化,沒有對新資源進行請求。

爲了解決這樣的問題,ETag也做爲Last-Modified的增強與補充出現了服務器

ETag

ETag是服務器給資源生成的標識字符串,做爲Last-Modified的增強與補充,他跟Last-Modified工做原理很類似,在資源的響應頭中生成ETag,在後續請求的請求頭中會生成If-None-Match,經過比對二者的差別,若是Last-Modified與ETag同時存在時,對ETag進行優先斷定異步

一樣ETag也是有其弊端,不一樣於文件修改系統默認會記錄其修改的時間,ETag的生成是須要額外的開銷,大量的資源生成會影響性能,若是沒有特殊要求使用Last-Modified已經能夠知足大多數需求了。

(對ETag與Last-Modified的補充)

Nginx下配置Last-Modified時(ETag是可配置的) Apache默認是二者都會返回

那麼問題來了ETag做爲Last-Modified的強化與補充若是隻有ETag是否也會觸發交互? 結果是:ETag能夠單獨使用,與服務端進行資源斷定

HTTP緩存指南

那對於這些資源設置應該是怎麼樣的呢?咱們這裏參考一下Chrome給出的流程圖

首先咱們須要確認資源是否是須要複用?若是不復用則將 cache-control設置爲 no-store,若是須要複用則將 cache-control設置爲 no-cache,隨後咱們根據資源是否是須要被代理服務器緩存來設置 public或者 private,最後再設置 max-age;最後在設置 Last-ModifiedETag等屬性。

MemoryCache與DiskCache

MemoryCache:在服務器內存空餘的時候優先使用Memory Cache隨後纔會考慮使用disk Cache, 由於Memory Cache讀取速度是最快的同時也是最短命的在瀏覽器關閉該頁面時就會銷燬資源,disk Cache讀取速度比Memory Cache要慢可是因爲它是存在硬盤中的因此它的存在時間是最長的也是最穩定的。

如圖在我關閉原有頁面後從新打開該頁面,沒有從memory cache中去獲取的資源,都是從disk cache中去獲取的

Service Worker Cache

上面介紹了httpcache又介紹了memoryCache,如今來介紹一下一個更陌生的service worker cache。 咱們書寫的js代碼一般是在主線程運行,能夠訪問DOM與Windows全局變量,Service Worker與Web Worker則是獨立於主線程的JavaScript線層,由於他被設計成徹底異步的,因此她不會阻塞頁面渲染也不會阻塞JavaScript主流程的執行因此咱們能夠用它去緩存離線資源,推送消息等。 同時Service Worker對協議也是有要求的,必須是https,可是這個對於咱們本地調試或者開發實際上是不友好的,不過還算Service Worker還算是人性化,能夠再localhost跟127.0.0.1環境下運行,同時github也能夠執行相關的代碼。 這裏咱們準備一個demo

咱們啓一個服務器(這裏我推薦使用live-server) 頁面第一次打開時Application下的cache Storage是沒有任何文件的,可是在看到控制檯中顯示

ServiceWorker registration successful with scope:  http://127.0.0.1:8080/
複製代碼

再看cache Storage,則會對出一條數據,他就是用於存儲本地文件, 咱們從新請求頁面會發現serviceWorker.html文件是從serviceworker中獲取的

Push Cache

【持續更新中....】

參考文獻 藉助Service Worker和cacheStorage緩存及離線開發 前端性能優化原理與實踐

相關文章
相關標籤/搜索