瀏覽器的緩存策略是依靠 HTTP Header 來實現的,共分爲兩種:web
強緩存是指在緩存期間,請求不會發送到服務器,瀏覽器直接返回緩存結果,須要設置 Header:算法
expires: Wed, 10 Oct 2020 09:51:00 GMT
expires 是 HTTP/1.0 中用於控制網頁緩存的字段,其值表明服務器返回該請求結果的緩存到期時間,也就是說,再次發起一樣的請求時,若是客戶端時間小於 Expires 的值,瀏覽器直接返回緩存結果。chrome
因爲 expires 是採用客戶端時間去和緩存失效時間作對比,但客戶端時間是能夠作修改的,若是客戶端時間和服務端時間並不一樣步,就會致使強緩存失效,或者時效變少。瀏覽器
因此,在 HTTP/1.1 中增長了 cache-control 頭。緩存
cache-control 常見值爲:服務器
咱們來看個例子:
網絡
這個例子中,expires 和 cache-control 都被設置了,可是 cache-control 優先級高,因此該資源會在 2592000 秒(也就是 30 天)後失效。學習
咱們能夠得出 2 個結論:this
當咱們 F12 查看瀏覽器網絡請求的時候,確定看到過這樣的信息,from memory cache(內存緩存)和 from disk cache(磁盤緩存)。spa
當請求命中強緩存時,瀏覽器就會從內存或者磁盤中將緩存的資源返回來,請求不會到達服務器。
那麼,哪些資源緩存在 memory,哪些緩存在 disk 呢?
關於 memory cache 和 disk cache,Chrome 官方有這麼一段描述:
Caching
Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, callhandlerBehaviorChanged()
to flush the in-memory cache. But don't do it often; flushing the cache is a very expensive operation. You don't need to callhandlerBehaviorChanged()
after registering or unregistering an event listener.
以上引用自 Chrome API
讀取 memory 中的緩存資源,確定要比讀取 disk 中的更快,可是 memory 中的緩存,會隨着進程的釋放而釋放,也就是說,一旦咱們關閉 Tab 標籤,memory 中的緩存也就沒有了。
那麼哪些資源會被緩存到 memory,哪些會緩存到 disk 中呢?關於這點我也沒有找到定論,大多數的觀點以下,供你們參考:
若是請求沒有命中強緩存,或者強緩存失效後,就須要向服務器發起請求,驗證資源是否有更新,這個過程叫作協商緩存。
當瀏覽器發起請求驗證資源時,若是資源沒有改變,那麼服務器返回 304 狀態碼,而且更新瀏覽器緩存有效期;若是資源發生改變,那麼服務器返回 200 狀態碼,而且返回相應資源,更新瀏覽器緩存有效期。
那麼服務器如何肯定資源有沒有更新呢,這裏就要用到如下 2 組 HTTP 頭。
last-modified 表示文件的最後修改日期,由服務器添加到 Response Header 中;if-modified-since 由瀏覽器添加到 Request Header 中,是上一次該資源的 last-modified 值。
服務器收到請求後,會將 if-modified-since 和服務器上該文件的修改時間戳進行比對,若是超過了緩存時間,那麼則返回最新的資源,200 狀態碼,若是還在緩存有效期內,則返回 304 狀態碼。
上面這個例子能夠看到:
Fri, 20 Dec 2019 12:44:01 GMT
Fri, 20 Dec 2019 12:44:01 GMT
這裏服務器將 if-modified-since 的時間和服務器上文件的修改時間作比對,發現仍在緩存時間有效期內,因此直接返回 304 狀態碼,並不返回文件資源,由瀏覽器提供緩存好的資源。
可是 last-modified 也有它的缺點:
由於以上這些問題,因而在 HTTP/1.1 出現了 etag / if-none-match。
etag 相似於文件指紋,能夠對文件內容作摘要算法,好比 md5,生成的值做爲 etag 的值,由服務器添加到 Response Header 中,瀏覽器再次請求該資源時,會在 Request Header 中添加 if-none-match 頭,值爲上次 etag 的值,服務器收到請求後,會對請求資源再次作相同的摘要算法,和 if-none-match 值進行比對,若是不同,說明資源更新了,返回 200 以及更新後的資源文件,若是相同,說明文件沒有被修改,則返回 304,由瀏覽器返回緩存資源。
總結來講,last-modified / if-modified-sice 和 etag / if-none-match,就是將服務器返回的某一個值,由瀏覽器在發送請求的時候帶回去,服務器拿到值後和本地文件的某個屬性進行判斷,來決定是否返回新的資源,仍是由瀏覽器返回緩存資源,這個過程,就叫作協商緩存。
相似於 expires 和 cache-control,etag / if-none-match 的優先級要比 last-modified / if-modified-since 高。
若是什麼緩存策略都沒有設置,那麼瀏覽器會採用一個啓發式的算法,一般會讀取 Response Header 中的 date 頭,減去 last-modified 值的 10% 做爲緩存時間。
學習了上面的緩存策略,在實際場景中咱們該如何應用呢?