瀏覽器的緩存機制對於前端性能優化來說是一個非常重要的環節,瀏覽器的緩存主要分爲兩類:強緩存和協商緩存,下面我們將分別介紹下這兩種緩存:
強緩存
瀏覽器在發起http請求時首先檢查的就是強緩存,該緩存機制中是不需要發送請求的,主要是通過攜帶字段確認實現,在早期的http1.0階段是通過Expires字段,後來的http1.1z中使用Cache-Control字段;
Expires
Expires是指過期時間,它存在服務器的響應頭中,用來告訴瀏覽器在這個過期時間之前是不需要請求的,可以直接使用緩存內容,此時返回304狀態碼,如果超過過期時間則需要發送請求服務器響應。在這個實現機制中存在一個坑點就是服務器的時間和瀏覽器的時間可能不一致,這樣就會導致過期時間不準確,所以後來的1.1中就拋棄了這個字段,使用了Cache-control字段。
Cache-Control
Cache-Control和Expires最大的區別是它不是採取的過期時間點,而是利用的過期時長,其中通過max-age屬性來傳達過期時長,如Cache-Control:max-age:3600,此時就表示在一個小時內都可以直接使用緩存內容。其中Cache-Control還有其他的屬性,如:
- public:表示客戶端和代理服務器都可以進行緩存
- private:表示只能客戶端緩存
- no-cache:表示跳過當前的強緩存,發起http請求,直接進入協商緩存
- no-store:表示不進行緩存
- s-maxage:表示針對代理服務器的緩存時間
如果在檢查中強緩存失效了,則會發起請求,進入到協商緩存。
協商緩存
在強緩存失效後,瀏覽器會在請求頭中攜帶緩存tag向服務器發起請求,服務器根據該tag值去判斷是否使用緩存,其中tag字段分爲Last-Modified和Etag
-
Last-modified
表示最後修改時間,瀏覽器在向服務器發起請求後,服務器會在響應頭中加上該字段,在瀏覽器下一次發送請求時,會在請求頭中攜帶If-Modified-Since字段,該字段的值就是服務器傳來的最後一次修改時間,服務器拿到這個字段值後會和自身的最後修改時間進行對比,如果該字段值小於最後修改時間,則返回304,告訴瀏覽器使用緩存內容,否則在返回200,新的資源。
-
Etag
表示服務器根據當前文件資源內容生成的唯一標識,服務器在響應頭中將該字段傳遞給瀏覽器,瀏覽器在下次請求時會將這個值作爲If-None-match字段的內容並放到請求頭中,服務器接收到If-None-Match後會跟服務器上的Etag進行對比,如果兩者不一樣,說明更新了,返回200,否則返回304,告訴瀏覽器使用緩存內容。
兩者對比:在精度上Etag是優於Last-modified的,因爲Etag是根據資源文件內容生成的唯一標識,因爲能準確感知到資源文件內容的變化,而Last-modified是通過時間點來感知,有可能1s內修改多次,此時就不能體現修改。在性能上Last-modified是優於Etag的,Last-Modified僅僅只是記錄一個時間點,而 Etag需要根據文件的具體內容生成哈希值。
緩存位置
瀏覽器的緩存位置共有四種,按照優先級來說分別爲:
- Service Woker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker
它是使Js運行在主線程之外,雖然自己脫離了瀏覽器,無法訪問dom元素,但是它可以實現離線緩存,消息推送等,其中離線緩存就是指Service Woker Cache,同時它也是PWA實現的重要機制。
Memory Cache
它是指內存緩存,它的效率是最快的,但是它的生命週期很短,當渲染進程結束後,它也就不復存在了。
Disk Cache
它是指硬盤緩存,它的存取效率會慢一些,但是它的存儲容量和存儲時長相對比較有優勢。
Push Cache
推送緩存是http2中的內容,目前應用不是恨廣泛,後續隨着http2的推廣,肯定會備受關注的
總結
瀏覽器在發送請求時,首先會檢查強緩存,如果強緩存命中,則不需要發送請求,直接從緩存中獲取資源數據,若是強緩存失效,則發送請求進入協商緩存,服務器通過瀏覽器請求頭中Last-Modified和Etag字段進行檢查,若是資源更新則返回新的資源數據,200狀態碼,否則返回304,告訴瀏覽器使用緩存資源數據即可。