最近宅在家學習了一下緩存知識,總結成文檔,和你們交流分享。說到緩存,有瀏覽器緩存、數據庫緩存、代理服務器緩存、CDN緩存等,咱們今天只聊瀏覽器緩存(其餘的涉及到個人知識盲區)。css
不少文章中提到的前端緩存、web緩存也都是瀏覽器緩存。前端
咱們都知道,瀏覽器請求時會先看看有沒有緩存,命中緩存就直接拿到資源,不用再去向服務器請求。省去了請求的時間,也減輕了服務器的壓力。那麼緩存都是放在哪裏的呢?git
緩存的四個位置按照優先級順序依次爲Service Worker、Memory Cache、Disk Cache和Push Cache。github
Service Worker能夠理解成瀏覽器和服務器之間的一個代理,比起Memory Cache 或是Disk Cache,Service Worker可讓咱們開發者來控制緩存哪些文件、如何匹配緩存、如何讀取等。出於安全考量,Service Worker只能用HTTPS來承載。web
若是Service Worker沒有命中緩存,那麼就會用fetch()
函數來獲取數據。這裏須要注意的是:通過fetch()
方法獲取的資源,不管是從Memory Cache中拿到的數據仍是網絡請求拿到的,都會顯示從Service Worker
中拿的。 像這樣:算法
Memory Cache就是瀏覽器放在內存中的緩存,內存咱們都知道:容量小,可是讀取速度快,因此一些小的資源就能夠在內存中緩存了。數據庫
打開一個網頁,打開控制檯,刷新一次,就能夠看到有的資源是從Memory Cache中拿到的。如圖: 瀏覽器
圖中看到Time那一欄的值,都是0ms(這裏是特例,不全都是0ms),能夠看到從內存中拿資源是很是快的,可是內存的容量比較小,時效性也比較低,Tab頁關掉,這些緩存就會失效了。緩存
Memory Cache裏面主要是圖片、js 、css文件,preload 預加載來的資源也會放在Memory Cache中。Memory Cache是不關心http首部字段的。設置的max-age
或是no-cache
都會被瀏覽器忽略掉。安全
真正關心http首部字段的人是Disk Cache,就是硬盤中的緩存。硬盤與上面的內存是互補的,硬盤容量大,時效性長(資源過時時間長),缺點就是讀取速度慢。
Disk Cache會根據HTTP請求的響應頭來判斷哪些資源能夠緩存、哪些資源過時了須要從新請求等。即便是不如內存的速度快,可是省去了網絡請求的話,速度也仍是提高了很多的。絕大部分的緩存都是來自於Disk Cache。
硬盤上的緩存,若是兩個站點共用了一張圖,是能夠共用的。
Push Cache 就是HTTP2的服務器端推送。是服務器端推測咱們可能須要的一些資源,提早推送到客戶端的緩存裏面來,等到客戶端須要,直接從緩存裏面拿就能夠了。
例如,咱們請求一個HTML,那麼確定須要這個頁面的圖片、css、js資源了,服務器端能夠提早推送。
好了,咱們如今來梳理一下整個流程:
fetch
方法前面說完了緩存的位置,下面咱們聊聊緩存的兩種方式:強緩存和協商緩存。
強緩存就是服務器端返回響應的時候,告訴客戶端多長時間這個資源不失效,直接用就好了,不用來問我。
強緩存主要是用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有不少可選的值,咱們說幾個經常使用的。(查看所有值)
若是能次次都命中強緩存那固然很好,省了網絡請求,網頁的響應速度那絕對的快。可是若是服務器上的資源更新了呢?那完蛋,咱們就拿到髒數據了。
因此協商緩存就要起做用了。協商緩存就是客戶端雖然緩存了,可是客戶端仍是得發請求到服務器去確認一下,資源過時沒?沒-> 304,拿緩存;過時了,200,返回響應內容。
協商緩存的兩個首部字段是:ETag和Last-Modified。準確地說是兩對兒:ETag & If-None-Match ;Last-Modified & If-Modified-Since。
ETag 是服務器端產生的一個hash字符串,用來標識一個資源的狀態。像這樣:
ETag: "82e222983df93"
服務器會爲每份資源分配對應的ETag,資源更新時,ETag也會更新。ETag的生成並無什麼統一的算法規則,看服務器怎麼生成了。
畫個圖吧。客戶端帶過去的If-None-Match就是服務器端返回的ETag,服務器端會把If-None-Match的值和存在服務器端的ETag值對比,一致則說明資源沒更新,不然,更新了。
Last-Modified: Thu, 10 Nov 2017 08:46:12 GMT
Last-Modified是服務器告訴咱們資源最後修改的時間。仍是上個圖吧,簡單又清晰。
Last-Modified相比於ETag,缺點在於:
目前的項目大多使用這種緩存方案的:
以上,若有錯漏,懇請指正!