
目的
瀏覽器緩存(Browser Caching)是為了節約網絡的資源加速瀏覽,瀏覽器在用戶磁盤上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁盤顯示文檔,這樣就可以加速頁面的閱覽。
簡單釋義
瀏覽器緩存其實就是瀏覽器保存通過HTTP獲取的所有資源,是瀏覽器將網絡資源存儲在本地的一種行為。瀏覽器的緩存機制是根據HTTP報文的緩存標識進行的。
策略
通常瀏覽器緩存策略分為兩種:強緩存(Expires,cache-control)和協商緩存(Last-modified ,Etag),並且緩存策略都是通過設置 HTTP Header 來實現的。
強制緩存
Expires
response header里的過期時間,瀏覽器再次加載資源時,如果在這個過期時間內,則命中強制緩存。
Cache-Control
當值設為max-age=300時,則代表在這個請求正確返回時間(瀏覽器也會記錄下來)的5分鍾內再次加載資源,就會命中強緩存。
Expires和Cache-Control的區別
- Expires 是http1.0的產物,Cache-Control是http1.1的產物
- 兩者同時存在的話,Cache-Control優先級高於Expires;
- 在某些不支持HTTP1.1的環境下,Expires就會發揮用處。所以Expires其實是過時的產物,現階段它的存在只是一種兼容性的寫法
- Expires是一個具體的服務器時間,這就導致一個問題,如果客戶端時間和服務器時間相差較大,緩存命中與否就不是開發者所期望的。Cache-Control是一個時間段,控制就比較容易
協商緩存
ETag和If-None-Match
這兩個要一起說。Etag是上一次加載資源時,服務器返回的response header,是對該資源的一種唯一標識,只要資源有變化,Etag就會重新生成。瀏覽器在下一次加載資源向服務器發送請求時,會將上一次返回的Etag值放到request header里的If-None-Match里,服務器接受到If-None-Match的值后,會拿來跟該資源文件的Etag值做比較,如果相同,則表示資源文件沒有發生改變,命中協商緩存。
Last-Modified和If-Modified-Since
這兩個也要一起說。Last-Modified是該資源文件最后一次更改時間,服務器會在response header里返回,同時瀏覽器會將這個值保存起來,在下一次發送請求時,放到request header里的If-Modified-Since里,服務器在接收到后也會做比對,如果相同則命中協商緩存。
ETag和Last-Modified區別
- 在方式上,Etag是對資源的一種唯一標識,而Last-Modified是該資源文件最后一次更改時間
- 在精確度上,Etag要優於Last-Modified。Last-Modified的時間單位是秒,如果某個文件在1秒內改變了多次,那么他們的Last-Modified其實並沒有體現出來修改,但是Etag每次都會改變確保了精度;如果是負載均衡的服務器,各個服務器生成的Last-Modified也有可能不一致。
- 在性能上,Etag要遜於Last-Modified,畢竟Last-Modified只需要記錄時間,而Etag需要服務器通過算法來計算出一個hash值。
- 在優先級上,服務器校驗優先考慮Etag。
瀏覽器緩存過程
- 瀏覽器第一次加載資源,服務器返回200,瀏覽器將資源文件從服務器上請求下載下來,並把response header及該請求的返回時間一並緩存;
- 下一次加載資源時,先比較當前時間和上一次返回200時的時間差,如果沒有超過cache-control設置的max-age,則沒有過期,命中強緩存,不發請求直接從本地緩存讀取該文件(如果瀏覽器不支持HTTP1.1,則用expires判斷是否過期);如果時間過期,則向服務器發送header帶有If-None-Match和If-Modified-Since的請求;
- 服務器收到請求后,優先根據Etag的值判斷被請求的文件有沒有做修改,Etag值一致則沒有修改,命中協商緩存,返回304;如果不一致則有改動,直接返回新的資源文件帶上新的Etag值並返回200;
- 如果服務器收到的請求沒有Etag值,則將If-Modified-Since和被請求文件的最后修改時間做比對,一致則命中協商緩存,返回304;不一致則返回新的last-modified和文件並返回200;
存儲位置
從存儲位置來看,瀏覽器緩存一共分為四種,並且各自有優先級,當依次查找緩存且都沒有命中的時候,才會去請求網絡。
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker
Service Worker 是運行在瀏覽器背后的獨立線程,一般可以用來實現緩存功能。使用 Service Worker的話,傳輸協議必須為 HTTPS。因為 Service Worker 中涉及到請求攔截,所以必須使用 HTTPS 協議來保障安全。Service Worker 的緩存與瀏覽器其他內建的緩存機制不同,它可以讓我們自由控制緩存哪些文件、如何匹配緩存、如何讀取緩存,並且緩存是持續性的。
Service Worker 實現緩存功能一般分為三個步驟:
- 首先需要先注冊 Service Worker
- 然后監聽到 install 事件以后就可以緩存需要的文件
- 那么在下次用戶訪問的時候就可以通過攔截請求的方式查詢是否存在緩存,存在緩存的話就可以直接讀取緩存文件,否則就去請求數據。
當 Service Worker 沒有命中緩存的時候,我們需要去調用 fetch 函數獲取數據。也就是說,如果我們沒有在 Service Worker 命中緩存的話,會根據緩存查找優先級去查找數據。但是不管我們是從 Memory Cache 中還是從網絡請求中獲取的數據,瀏覽器都會顯示我們是從 Service Worker 中獲取的內容。
Memory Cache
Memory Cache 也就是內存中的緩存,主要包含的是當前中頁面中已經抓取到的資源,例如頁面上已經下載的樣式、腳本、圖片等。讀取內存中的數據肯定比磁盤快,內存緩存雖然讀取高效,可是緩存持續性很短,會隨着進程的釋放而釋放。 一旦我們關閉 Tab 頁面,內存中的緩存也就被釋放了。
⚠️:內存緩存在緩存資源時並不關心返回資源的HTTP緩存頭Cache-Control是什么值,同時資源的匹配也並非僅僅是對URL做匹配,還可能會對Content-Type,CORS等其他特征做校驗。
Disk Cache
Disk Cache 也就是存儲在硬盤中的緩存,讀取速度慢點,但是什么都能存儲到磁盤中,比之 Memory Cache 勝在容量和存儲時效性上。它會根據 HTTP Herder 中的字段判斷哪些資源需要緩存,哪些資源可以不請求直接使用,哪些資源已經過期需要重新請求。並且即使在跨站點的情況下,相同地址的資源一旦被硬盤緩存下來,就不會再次去請求數據。絕大部分的緩存都來自 Disk Cache。
Push Cache
Push Cache(推送緩存)是 HTTP/2 中的內容,當以上三種緩存都沒有命中時,它才會被使用。它只在會話(Session)中存在,一旦會話結束就被釋放,並且緩存時間也很短暫,在Chrome瀏覽器中只有5分鍾左右,同時它也並非嚴格執行HTTP頭中的緩存指令。他有如下的一些特性:
- 所有的資源都能被推送,並且能夠被緩存,但是 Edge 和 Safari 瀏覽器支持相對比較差。
- Push Cache 中的緩存只能被使用一次
- 可以給其他域名推送資源
- 瀏覽器可以拒絕接受已經存在的資源推送
- 一旦連接被關閉,Push Cache 就被釋放
- 可以推送 no-cache 和 no-store 的資源
- 多個頁面可以使用同一個HTTP/2的連接,也就可以使用同一個Push Cache。這主要還是依賴瀏覽器的實現而定,出於對性能的考慮,有的瀏覽器會對相同域名但不同的tab標簽使用同一個HTTP連接。
用戶行為對瀏覽器緩存的控制
- 地址欄訪問,鏈接跳轉是正常用戶行為,將會觸發瀏覽器緩存機制;
- F5刷新,瀏覽器會設置max-age=0,跳過強緩存判斷,會進行協商緩存判斷;
- ctrl+F5刷新,跳過強緩存和協商緩存,直接從服務器拉取資源。
三級緩存原理 (訪問緩存優先級)
- 先在內存中查找,如果有,直接加載。
- 如果內存中不存在,則在硬盤中查找,如果有直接加載。
- 如果硬盤中也沒有,那么就進行網絡請求。
- 請求獲取的資源緩存到硬盤和內存。
問題
內存緩存和硬盤緩存有什么區別?
口訣:存速時空(存的速食都被我吃空了)
區別 |
內存緩存 |
硬盤緩存 |
存儲內容 |
JS,字體,圖片等 |
CSS等 |
讀取速度 |
快 |
慢 |
時效性 |
進程關閉則清空 |
可以緩存較長時間 |
空間 |
空間小 |
空間大 |
1.內存緩存(from memory cache):內存緩存主要的兩個特點,分別是快速讀取和時效性:
- 快速讀取:內存緩存會將編譯解析后的文件,直接存入該進程的內存中,占據該進程一定的內存資源,以方便下次運行使用時的快速讀取。一般JS,字體,圖片等會放在內存緩存中
- 時效性:一旦該進程關閉,則該進程的內存則會清空。
2.硬盤緩存(from disk cache):硬盤緩存則是直接將緩存寫入硬盤文件中,讀取緩存需要對該緩存存放的硬盤文件進行I/O操作,然后重新解析該緩存內容,讀取復雜,速度比內存緩存慢。退出進程不會清空。一般JS,字體,圖片等會放在內存中,而CSS則會放在硬盤緩存中
瀏覽器的緩存存放在哪里,如何在瀏覽器中判斷強制緩存是否生效?
判斷是否命中強制緩存:當命中強制緩存時,狀態碼為200, 請求對應的Size值則代表該緩存存放的位置,分別為from memory cache 和 from disk cache。from memory cache代表使用內存中的緩存,from disk cache則代表使用的是硬盤中的緩存,瀏覽器讀取緩存的順序為memory > disk。
為什么CSS會放在硬盤緩存中?
因為CSS文件加載一次就可渲染出來,我們不會頻繁讀取它,所以它不適合緩存到內存中,但是js之類的腳本卻隨時可能會執行,如果腳本在磁盤當中,我們在執行腳本的時候需要從磁盤取到內存中來,這樣IO開銷就很大了,有可能導致瀏覽器失去響應。
那么既然內存緩存這么高效,我們是不是能讓數據都存放在內存中呢?
這是不可能的。計算機中的內存一定比硬盤容量小得多,操作系統需要精打細算內存的使用,所以能讓我們使用的內存必然不多。
參考資料
https://zhuanlan.zhihu.com/p/25953524
https://www.jianshu.com/p/54cc04190252
https://segmentfault.com/a/1190000017962411