從緩存位置上來說分為四種,并且各自有優(yōu)先級,當(dāng)依次查找緩存且都沒有命中的時候,才會去請求網(wǎng)絡(luò)。
Service Worker / Memory Cache / Disk Cache / Push Cache
Service Worker
Service Worker 是運行在瀏覽器后臺的獨立線程,可以用來實現(xiàn)緩存。由于 Service Worker 中涉及到請求攔截,所以必須是 Https協(xié)議的請求。Service Worker 的緩存與瀏覽器其他內(nèi)建的緩存機制不同,它可以讓我們自由控制緩存哪些文件、如何匹配緩存、如何讀取緩存,并且緩存是持續(xù)性的。
當(dāng) Service Worker 沒有命中緩存的時候,我們需要去調(diào)用 fetch 函數(shù)獲取數(shù)據(jù)。也就是說,如果我們沒有在 Service Worker 命中緩存的話,會根據(jù)緩存查找優(yōu)先級去查找數(shù)據(jù)。但是不管我們是從 Memory Cache 中還是從網(wǎng)絡(luò)請求中獲取的數(shù)據(jù),瀏覽器都會顯示我們是從 Service Worker 中獲取的內(nèi)容。
Service Worker 實現(xiàn)緩存一般分為三步:
首先注冊 Service Worker;
監(jiān)聽到 install 事件后緩存需要的文件;
用戶下次請求的時候查詢是否存在緩存,存在直接讀取緩存文件,否則就去請求數(shù)據(jù)。
Memory Cache
內(nèi)存中的緩存。一般網(wǎng)頁中已經(jīng)抓取到的資源會被放入內(nèi)存緩存,比如已經(jīng)下載的樣式、腳本、圖片等等。
內(nèi)存緩存雖然讀取高效,可是緩存持續(xù)性很短,會隨著進程的釋放而釋放。一般我們關(guān)閉tab頁面以后緩存就會被釋放。
內(nèi)存緩存在緩存資源時并不關(guān)心返回資源的HTTP緩存頭Cache-Control是什么值,同時資源的匹配也并非僅僅是對URL做匹配,還可能會對Content-Type,CORS等其他特征做校驗。
內(nèi)存緩存中有一塊重要的緩存資源是preloader相關(guān)指令,例如<link rel="preload" href="sintel-short.mp4">,
preload預(yù)加載也是前端優(yōu)化的常用手段。
Disk Cache
硬盤中的緩存。相比內(nèi)存緩存讀取速度更慢,但是沒有任何限制,容量和生命周期都更好。它會根據(jù) HTTP Herder 中的字段判斷哪些資源需要緩存,哪些資源可以不請求直接使用,哪些資源已經(jīng)過期需要重新請求。
瀏覽器對 memory Cache 和 disk cache 存儲優(yōu)先級:
* 對于大文件來說,大概率是不存儲在內(nèi)存中的,反之優(yōu)先
* 當(dāng)前系統(tǒng)內(nèi)存使用率高的話,文件優(yōu)先存儲進硬盤
Push Cache
推送緩存是Http2.0才有的,當(dāng)以上的緩存沒有命中才會被使用。他只會在 Session 中存在,一旦會話結(jié)束就被釋放,緩存時間也很短暫。在Chrome瀏覽器中只有5分鐘左右,同時它也并非嚴(yán)格執(zhí)行HTTP頭中的緩存指令。
關(guān)于推送緩存的一特性:
* 所有的資源都能被推送,并且能夠被緩存,但是 Edge 和 Safari 瀏覽器支持相對比較差
* 可以推送 no-cache 和 no-store 的資源
* 一旦連接被關(guān)閉,Push Cache 就被釋放
* 多個頁面可以使用同一個HTTP/2的連接,也就可以使用同一個Push Cache。這主要還是依賴瀏覽器的實現(xiàn)而定,出于對性能的考慮,有的瀏覽器會對相同域名但不同的tab標(biāo)簽使用同一個HTTP連接。
* Push Cache 中的緩存只能被使用一次
* 瀏覽器可以拒絕接受已經(jīng)存在的資源推送
* 你可以給其他域名推送資源
緩存過程

1.瀏覽器每次發(fā)起請求,都會先在瀏覽器緩存中查找該請求的結(jié)果以及緩存標(biāo)識
2.瀏覽器每次拿到返回的請求結(jié)果都會將該結(jié)果和緩存標(biāo)識存入瀏覽器緩存中
根據(jù)是否需要向服務(wù)器重新發(fā)起HTTP請求,分為 強緩存和*協(xié)商緩存*兩種緩存策略
緩存策略
瀏覽器緩存策略分為兩類:強緩存和協(xié)商緩存,緩存策略通過 HTTP 頭部 Header 來設(shè)置。
強緩存
不會向服務(wù)器發(fā)送請求,直接從緩存中讀取資源,在chrome控制臺的Network選項中可以看到該請求返回200的狀態(tài)碼,并且Size顯示from disk cache或from memory cache。強緩存可以通過設(shè)置兩種 HTTP Header 實現(xiàn):Expires 和Cache-Control。
Cache-Control
可以通過 Cache-Ccontrol 控制緩存的工作機制。
--指令--說明public所有內(nèi)容都將被緩存private所有內(nèi)容只有客戶端會被緩存,中間節(jié)點不允許緩存no-cache客戶端緩存內(nèi)容,使用緩存則需要經(jīng)過協(xié)商緩存來驗證決定no-store所有內(nèi)容都不會被緩存,即不使用強制緩存,也不使用協(xié)商緩存max-agemax-age=xxx (xxx is numeric)表示緩存內(nèi)容將在xxx秒后失效s-maxage同max-age作用一樣,只在代理服務(wù)器中生效(比如CDN緩存),如果存在s-maxage,則會覆蓋掉max-age和Expires headermax-stale能容忍的最大過期時間,如果沒有指定,那么說明瀏覽器愿意接收任何age的響應(yīng)min-fresh能夠容忍的最小新鮮度,min-fresh標(biāo)示了客戶端不愿意接受新鮮度不多于當(dāng)前的age加上min-fresh設(shè)定的時間之和的響應(yīng)。可以結(jié)合多個指令,實現(xiàn)不同的緩存功能:

Expires
指定緩存資源的過期時間(),Expires 是服務(wù)器響應(yīng)實體首部字段。如果在 Cache-Control 響應(yīng)頭設(shè)置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 頭會被忽略。同時注意,如果修改本地時間打過 Expires 的時間會造成緩存失效。
示例:
Expires: Wed, 21 Oct 2015 07:28:00 GMT
兩者對比
兩者差別不大,區(qū)別就在于 Expires 是http1.0的產(chǎn)物,Cache-Control 是http1.1的產(chǎn)物,兩者同時存在的話, Cache-Control 優(yōu)先級高于 Expires ,現(xiàn)階段 Expires 更多的是用于兼容的寫法。
協(xié)商緩存
協(xié)商緩存就是強制緩存失效后,瀏覽器攜帶緩存標(biāo)識向服務(wù)器發(fā)起請求,由服務(wù)器根據(jù)緩存標(biāo)識決定是否使用緩存的過程。協(xié)商返回會有兩種狀態(tài):
1.協(xié)商緩存生效,返回 304 Not Modified 狀態(tài)碼:

2.協(xié)商緩存失敗,返回 200 狀態(tài)碼:

協(xié)商緩存可以通過設(shè)置 Last-Modified 和 ETag 實現(xiàn):
Last-Modified
該字段為響應(yīng)實體的頭部字段,指明資源在服務(wù)器上最后的修改時間。
過程:
- 瀏覽器接受有 Last-Modified 字段的響應(yīng)后會緩存文件和header。
- 瀏覽器再次請求這個資源的時候,檢測到有 Last-Modified 這個header,然后在header中添加 If-Modified-Since 這個字段,值為 Last-Modified 的值。
- 服務(wù)器再次收到這個資源請求,會根據(jù) If-Modified-Since 中的值與服務(wù)器中這個資源的最后修改時間對比,如果沒有變化,返回304和空的響應(yīng)體,直接從緩存讀取,如果 If-Modified-Since 的時間小于服務(wù)器中這個資源的最后修改時間,說明文件有更新,于是返回新的資源文件和200。
缺點:
- 如果本地打開緩存文件,即使沒有對文件進行修改,但還是會造成 Last-Modified 被修改,服務(wù)端不能命中緩存導(dǎo)致發(fā)送相同的資源。
- 因為 Last-Modified 只能以秒計時,如果在不可感知的時間內(nèi)(毫秒級)修改完成文件,那么服務(wù)端會認(rèn)為資源還是命中了,不會返回正確的資源。
ETag
Etag是服務(wù)器響應(yīng)請求時,返回當(dāng)前資源文件的一個唯一標(biāo)識(由服務(wù)器生成),只要資源有變化,Etag就會重新生成。
瀏覽器在下一次加載資源向服務(wù)器發(fā)送請求時,會將上一次返回的 Etag 值放到request header里的If-None-Match里,服務(wù)器只需要比較客戶端傳來的 If-None-Match 跟自己服務(wù)器上該資源的ETag是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。
兩者對比
- 精確度上,Etag 要優(yōu)于 Last-Modified,Last-Modified 單位是秒,可能文件一秒內(nèi)更新了多次而沒有返回,并且負(fù)載均衡的服務(wù)器生成的 Last-Modified 也可能不一樣。
- 性能上,Last-Modified 要優(yōu)于 Etag,因為 Last-Modified 只需要記錄時間,而 Etag 還需要計算出一個 hash值。
- 優(yōu)先級上,服務(wù)器會優(yōu)先考慮 Etag。
緩存機制
- 強制緩存優(yōu)先于協(xié)商緩存進行,若強制緩存(Expires和Cache-Control)生效則直接使用緩存;
- 若強緩存不生效則進行協(xié)商緩存(Last-Modified / If-Modified-Since和Etag / If-None-Match);
- 協(xié)商緩存由服務(wù)器決定是否使用緩存,若協(xié)商緩存失效,那么代表該請求的緩存失效,返回200,重新返回資源和緩存標(biāo)識,再存入瀏覽器緩存中;生效則返回304,繼續(xù)使用緩存;
- 若什么策略都沒有,瀏覽器會采用一個啟發(fā)式算法,通常會取響應(yīng)頭中的 Date 減去 Last-Modified 值的 10% 作為緩存時間。