聊聊瀏覽器緩存

前言

最近宅在家學習了一下緩存知識,總結成文檔,和你們交流分享。說到緩存,有瀏覽器緩存、數據庫緩存、代理服務器緩存、CDN緩存等,咱們今天只聊瀏覽器緩存(其餘的涉及到個人知識盲區)。css

不少文章中提到的前端緩存、web緩存也都是瀏覽器緩存。前端

緩存位置

咱們都知道,瀏覽器請求時會先看看有沒有緩存,命中緩存就直接拿到資源,不用再去向服務器請求。省去了請求的時間,也減輕了服務器的壓力。那麼緩存都是放在哪裏的呢?git

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache

緩存的四個位置按照優先級順序依次爲Service Worker、Memory Cache、Disk Cache和Push Cache。github

Service Worker

Service Worker能夠理解成瀏覽器和服務器之間的一個代理,比起Memory Cache 或是Disk Cache,Service Worker可讓咱們開發者來控制緩存哪些文件、如何匹配緩存、如何讀取等。出於安全考量,Service Worker只能用HTTPS來承載。web

若是Service Worker沒有命中緩存,那麼就會用fetch() 函數來獲取數據。這裏須要注意的是:通過fetch()方法獲取的資源,不管是從Memory Cache中拿到的數據仍是網絡請求拿到的,都會顯示從Service Worker中拿的。 像這樣:算法

Memory Cache

Memory Cache就是瀏覽器放在內存中的緩存,內存咱們都知道:容量小,可是讀取速度快,因此一些小的資源就能夠在內存中緩存了。數據庫

打開一個網頁,打開控制檯,刷新一次,就能夠看到有的資源是從Memory Cache中拿到的。如圖: 瀏覽器

圖中看到Time那一欄的值,都是0ms(這裏是特例,不全都是0ms),能夠看到從內存中拿資源是很是快的,可是內存的容量比較小,時效性也比較低,Tab頁關掉,這些緩存就會失效了。緩存

Memory Cache裏面主要是圖片、js 、css文件,preload 預加載來的資源也會放在Memory Cache中。Memory Cache是不關心http首部字段的。設置的max-age或是no-cache都會被瀏覽器忽略掉。安全

Disk Cache

真正關心http首部字段的人是Disk Cache,就是硬盤中的緩存。硬盤與上面的內存是互補的,硬盤容量大,時效性長(資源過時時間長),缺點就是讀取速度慢。

Disk Cache會根據HTTP請求的響應頭來判斷哪些資源能夠緩存、哪些資源過時了須要從新請求等。即便是不如內存的速度快,可是省去了網絡請求的話,速度也仍是提高了很多的。絕大部分的緩存都是來自於Disk Cache。

硬盤上的緩存,若是兩個站點共用了一張圖,是能夠共用的。

Push Cache

Push Cache 就是HTTP2的服務器端推送。是服務器端推測咱們可能須要的一些資源,提早推送到客戶端的緩存裏面來,等到客戶端須要,直接從緩存裏面拿就能夠了。

例如,咱們請求一個HTML,那麼確定須要這個頁面的圖片、css、js資源了,服務器端能夠提早推送。

好了,咱們如今來梳理一下整個流程:

  1. Service Worker,命中緩存,返回資源;不然調用fetch方法
  2. 查看Memory Cache,命中緩存,返回資源;不然到第3步
  3. 查看Disk Cache,命中緩存,返回資源,不然到第4步
  4. 查看Push Cache
  5. 沒有命中緩存,進行網絡請求
  6. 把響應內容存到Disk Cache
  7. 把響應內容的引用存到memory cache
  8. 把響應內容存入Service Worker

強緩存 & 協商緩存

前面說完了緩存的位置,下面咱們聊聊緩存的兩種方式:強緩存和協商緩存。

強緩存

強緩存就是服務器端返回響應的時候,告訴客戶端多長時間這個資源不失效,直接用就好了,不用來問我。

強緩存主要是用Cache-Control和Expires這兩個首部字段來控制。

Expires字段的值是資源的失效時間。像這樣:

Thu, 10 Nov 2017 08:46:12 GMT

這個字段的缺陷在於,客戶端的時間能夠用戶手動改掉,致使緩存失效。他是http 1.0的字段,目前基本上不會用了,用到只是爲了兼容。你們瞭解一下就好。max-age的優先級比Expires高。

Cache-Control的max-age字段(單位:秒)能夠設置資源在多少秒以後過時。像這樣:

Cache-Control:max-age=500

表示500s內這個資源都無須向服務器確認,瀏覽器再次請求會直接命中緩存,使用緩存就行了。

Cache-Control有不少可選的值,咱們說幾個經常使用的。(查看所有值

  • no-store,不容許緩存,每次請求都必須從源服務器請求資源
  • no-cache,能夠緩存,可是每次得先去服務器確認是否過時
  • public,代理服務器和客戶端均可以緩存
  • private,只有客戶端能夠緩存
  • s-maxage,和max-age含義同樣,可是隻對代理服務器有效

協商緩存

若是能次次都命中強緩存那固然很好,省了網絡請求,網頁的響應速度那絕對的快。可是若是服務器上的資源更新了呢?那完蛋,咱們就拿到髒數據了。

因此協商緩存就要起做用了。協商緩存就是客戶端雖然緩存了,可是客戶端仍是得發請求到服務器去確認一下,資源過時沒?沒-> 304,拿緩存;過時了,200,返回響應內容。

協商緩存的兩個首部字段是:ETag和Last-Modified。準確地說是兩對兒:ETag & If-None-Match ;Last-Modified & If-Modified-Since。

ETag

ETag 是服務器端產生的一個hash字符串,用來標識一個資源的狀態。像這樣:

ETag: "82e222983df93"

服務器會爲每份資源分配對應的ETag,資源更新時,ETag也會更新。ETag的生成並無什麼統一的算法規則,看服務器怎麼生成了。

畫個圖吧。客戶端帶過去的If-None-Match就是服務器端返回的ETag,服務器端會把If-None-Match的值和存在服務器端的ETag值對比,一致則說明資源沒更新,不然,更新了。

Last-Modified

Last-Modified: Thu, 10 Nov 2017 08:46:12 GMT

Last-Modified是服務器告訴咱們資源最後修改的時間。仍是上個圖吧,簡單又清晰。

Last-Modified相比於ETag,缺點在於:

  1. Last-Modified只能精確到秒,若是1秒內,資源改了兩次,那就出事了。
  2. 資源的最後修改時間改了,可是內容沒改,Last-Modified仍是會算做資源被修改了,而ETag不會。

緩存策略應用

目前的項目大多使用這種緩存方案的:

  • HTML: 協商緩存;
  • css、js、圖片:強緩存,文件名帶上hash。

瀏覽器行爲

  • 地址欄輸入網址:查找Disk Cache,命中緩存,拿到資源,不然發起網絡請求。
  • 刷新網頁:先查看Memory Cache,沒有命中緩存的話再去Disk Cache。
  • 強制刷新:不使用緩存,去服務器請求。

以上,若有錯漏,懇請指正!

參考文章

相關文章
相關標籤/搜索