前端緩存主要是分為 HTTP緩存 和 瀏覽器緩存。
其中HTTP緩存是在HTTP請求傳輸時用到的緩存,主要在服務器代碼上設置;而瀏覽器緩存則主要由前端開發在前端js上進行設置。
緩存可以說是性能優化中簡單高效的一種優化方式了。一個優秀的緩存策略可以縮短網頁請求資源的距離,減少延遲,並且由於緩存文件可以重復利用,還可以減少帶寬,降低網絡負荷。
緩存過程分析
瀏覽器第一次向服務器發起該請求后拿到請求結果,會根據 響應報文 中 HTTP頭的緩存標識,決定是否緩存結果,是則將請求結果和緩存標識存入瀏覽器緩存中,
由上圖我們可以知道:
瀏覽器每次發起請求,都會先在瀏覽器緩存中查找該請求的結果以及緩存標識
瀏覽器每次拿到返回的請求結果都會將該結果和緩存標識存入瀏覽器緩存中
強制緩存
強制緩存就是向瀏覽器緩存查找該請求結果,並根據該結果的緩存規則來決定是否使用該緩存結果的過程。
強制緩存的情況主要有三種,如下:
①不存在該緩存結果和緩存標識,強制緩存失效,則直接向服務器發起請求(跟第一次發起請求一致),如下圖:
②存在該緩存結果和緩存標識,但該結果已失效,強制緩存失效,則使用協商緩存,如下圖
③存在該緩存結果和緩存標識,且該結果尚未失效,強制緩存生效,直接返回該結果,如下圖
那么強制緩存的緩存規則是什么?
Expires
Expires是HTTP/1.0控制網頁緩存的字段,其值為服務器返回該請求結果緩存的到期時間,即再次發起該請求時,如果客戶端的時間小於Expires的值時,直接使用緩存結果。
到了HTTP/1.1,Expire已經被Cache-Control替代,原因在於Expires控制緩存的原理是使用客戶端的時間與服務端返回的時間做對比,那么如果客戶端與服務端的時間因為某些原因(例如時區不同;客戶端和服務端有一方的時間不准確)發生誤差,那么強制緩存則會直接失效,這樣的話強制緩存的存在則毫無意義。
Cache-Control
在HTTP/1.1中,Cache-Control是最重要的規則,主要用於控制網頁緩存,主要取值為:
- public:所有內容都將被緩存(客戶端和代理服務器都可緩存)
- private:所有內容只有客戶端可以緩存,Cache-Control的默認取值
- no-cache:客戶端緩存內容,但是是否使用緩存則需要經過協商緩存來驗證決定
- no-store:所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存
- max-age=xxx (xxx is numeric):緩存內容將在xxx秒后失效
接下來,我們直接看一個例子,如下:
由上面的例子我們可以知道:
①HTTP響應報文中expires的時間值,是一個絕對值
②HTTP響應報文中Cache-Control為max-age=600,是相對值
由於Cache-Control的優先級比expires高,那么直接根據Cache-Control的值進行緩存,意思就是說在600秒內再次發起該請求,則會直接使用緩存結果,強制緩存生效。
注:在無法確定客戶端的時間是否與服務端的時間同步的情況下,Cache-Control相比於expires是更好的選擇,所以同時存在時,只有Cache-Control生效。
了解強制緩存的過程后,我們進行下一步思考:瀏覽器的緩存存放在哪里,如何在瀏覽器中判斷強制緩存是否生效?
這里我們以博客的請求為例,狀態碼為灰色的請求則代表使用了強制緩存,請求對應的Size值則代表該緩存存放的位置,分別為 from memory cache 和 from disk cache。
么from memory cache 和 from disk cache又分別代表的是什么呢?什么時候會使用from disk cache,什么時候會使用from memory cache呢?
from memory cache代表使用內存中的緩存,
from disk cache則代表使用的是硬盤中的緩存,
瀏覽器讀取緩存的順序為memory –> disk –> 服務器請求。
那么接下來我們一起詳細分析一下緩存讀取問題,這里仍讓以我的博客為例進行分析:
首次訪問頁面

關閉博客的標簽頁,重新打開頁面

刷新頁面

內存緩存(from memory cache):內存緩存具有兩個特點,分別是速度快和時間限制。
硬盤緩存(from disk cache):硬盤緩存則是直接將緩存寫入硬盤文件中,讀取緩存需要對該緩存存放的硬盤文件進行I/O操作,然后重新解析該緩存內容,讀取復雜,速度比內存緩存慢。
協商緩存
協商緩存就是強制緩存失效后(這里只是失效,不是不存在了),瀏覽器攜帶緩存標識向服務器發起請求,由服務器根據緩存標識決定是否使用緩存的過程,主要有以下兩種情況:
①協商緩存生效,返回304,如下

②協商緩存失效,返回200和請求結果結果,如下

Last-Modified / If-Modified-Since
Last-Modified是服務器響應請求時,返回該資源文件在服務器最后被修改的時間,如下。

Etag / If-None-Match
Etag是服務器響應請求時,返回當前資源文件的一個唯一標識(由服務器生成),如下。


總結
