前端123:瀏覽器緩存的工作方式

瀏覽器緩存的工作流程


     通過網絡獲取內容既速度緩慢又開銷巨大。較大的響應需要在客戶端與服務器之間進行多次往返通信,這會延遲瀏覽器獲得和處理內容的時間,還會增加訪問者的流量費用。因此,緩存並重複利用之前獲取的資源的能力成爲性能優化的一個關鍵方面。

     這裏先看張大家最熟悉的Devtools網絡圖:

圖中青色、綠色和橙色圈出的部分分別是來自內存(memory緩存)、磁盤(disk緩存)和Http請求拿到的數據(非緩存),還有一種返回碼304的請求也是從緩存(memory/disk)中獲取數據。304跟memory/disk緩存的區別是:在瀏覽器判斷資源已經過期的情況下會去服務器查詢資源是否更新,如果資源沒更新則返回304碼,瀏覽器收到304碼就會更新資源的過期時間並直接從之前disk/memory緩存中拿到當前資源,換言之如果資源沒過期,那麼瀏覽器就會跳過向服務器校驗資源這一步並直接去拿memory/disk緩存獲取。

大致流程如下:

  • 1)首先檢查是否存在 Service Worker Cache,沒命中或不存在則進行下一步

  • 2)檢查內存中是否存在資源,存在的話直接加載(from memory - 200)。

  • 3)如果內存沒有,擇取從硬盤獲取,存在且沒過期的話直接加載(from disk - 200),過期了直接向服務器發送請求獲取資源。如果資源沒更新,服務器返回304,瀏覽器從硬盤緩存中獲取資源,並更新過期時間/Etag/Last-Modified。如果資源更新了則獲取最新的資源,並通過HTTP請求將資源返回,重新緩存資源並更新過期時間/Etag/Last-Modified

  • 4)如果硬盤也沒有,那麼會向後端發送HTTP網絡請求。

  • 5)加載到的資源緩存到硬盤和內存,並更新資源的過期時間/Etag/Last-Modified

     Service Worker Cache具有較高的優先級,數據控制更爲複雜,操作自由度最高;Memory Cache更多的強調了一種緩存存儲方式和瀏覽器內存緩存策略;HTTP Cache相對於Memory Cache根據存儲方式的不同也能叫做Disk Cache,它依賴於整個HTTP緩存校驗流程(強緩存和協商緩存),並通過校驗來最終確定何時從緩存讀取,何時從服務器更新資源;Push Cache資料較少,應用得不多,暫時只做介紹。

Service-Worker Cache(優先級最高)


     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 是什麼值,換句話說這是一種強依賴於瀏覽器本地內存管理策略的緩存方式,各個瀏覽器對內存緩存的處理方式也略有區別。

     Memory Cache遵循這些策略:

  • 對於大文件來說,大概率是不存儲在內存中的,反之優先
  • 當前系統內存使用率高的話,文件優先存儲進硬盤

* HTTP Cache(優先級次之)


     HTTP緩存根據工作方式分爲強緩存協商緩存,瀏覽器首先會判斷強緩存是否命中,命中失敗纔會嘗試進行協商緩存

1)強緩存

  • > HTTP 1.0時代 - expires
         我們通過瀏覽器獲取服務器遠程資源時,服務器通過http請求response headers返回一個expires時間戳字段(上圖中藍色部分),例如expires: Wed, 13 Oct 2021 22:15:05 GMT,表明這個資源的過期時間爲格林威治時間2021年10月13日 週三 22:15:05(北京時間+8h=格林威治時間),瀏覽器判斷當前時間在資源過期時間之前的話,就會從緩存中去讀取資源(如果緩存中存在的話),否則會重新向服務器發送請求。
         expires的工作機制要求客戶端時間與服務器時間誤差較小,否則緩存更新策略可能在短時間不生效。

  • > HTTP 1.1時代 - cache-control
         cache-control: max-age方式也是通過服務器返回資源時攜帶的response headers中的相應字段實現的,比如:cache-control: max-age=31536000,表明資源距瀏覽器接收到此資源後的31536000秒後過期。與expires返回的時間戳方式不同,cache-control爲了避免時間誤差,直接返回一個時間長度,瀏覽器可以根據一個本地時間差值進行精確判斷。
    cache-control其它相關字段還有:
         i.public/private:在依賴各種代理的大型架構中,我們不得不考慮代理服務器的緩存問題,public 與 private 用來控制代理服務緩存是否能緩存資源。如果我們爲資源設置了 public,那麼它既可以被瀏覽器緩存,也可以被代理服務器緩存;如果我們設置了 private,則該資源只能被瀏覽器緩存。private 爲默認值,不過在只設置s-maxage的情況下,代理緩存也能生效。
         ii.s-maxage:針對於代理服務器的緩存問題,此字段用於表示 cache 服務器上(比如 cache CDN)的緩存的有效時間的,只對 public 緩存有效,cache-control: max-age=3600, s-maxage=31536000
         iii.no-cache:爲資源設置了 no-cache 後,每一次發起請求都不會再去詢問瀏覽器的緩存情況,而是直接向服務端去確認該資源是否過期,直接進行協商緩存
         iv.no-store:不使用任何緩存策略,每次請求都直接從服務器獲取,並在瀏覽器客戶端不進行資源緩存。

  • > cache-control 和 expires 並存
         expires的優先級更高,當cache-control與 expires同時出現時,以cache-control爲準,不過考慮向下兼容性可以選擇同時使用兩種緩存策略。

2)協商緩存

     協商緩存依賴於服務端與瀏覽器之間的通信,在第一次獲取資源時瀏覽器會存儲HTTP請求的response headers字段:Last-Modified / Etag,當強緩存未命中的時候,它的值作爲瀏覽器和服務器通信時攜帶的標誌位用於判斷資源是否過期,如果服務器判斷資源過期的話就會重新下載資源,並更新相應標誌位。如果判斷資源未更新的話,會返回304狀態碼,瀏覽器就會複用客戶端緩存資源。

  • > Last-Modified 和 If-Modified-Since 方式
         Last-Modified爲隨服務器端HTTP響應頭部返回的時間戳標誌,表示一個資源最近一次被更新的時間,客戶端請求資源時添加上request headers字段If-Modified-Since(值與Last-Modified相同)用於服務器做校驗判斷資源是否更新,Last-Modified: Wed, 13 Jan 2021 15:34:55 GMT
    使用 Last-Modified 存在一些弊端:
         i. 命中失誤1: 當我們更新了服務器的某個資源文件,但其實際內容並未發生變化,其相應的資源更新時間戳會改變,瀏覽器端在服務端文件並未發生改變的情況下,僅僅通過時間戳這種判斷方式也會導致資源被完全重新下載。
         ii. 命中失誤2: If-Modified-Since 只能檢查到以秒爲最小計量單位的時間差,感知不到1s以內的文件改動的情況,這會導致一些瀏覽器緩存更新不及時的情況。

  • > Etag 和 If-None-Match 方式
         Etag就是爲了彌補Last-Modified的弊端而產生的新的協商緩存方式。Etag爲隨服務器端HTTP請求頭部返回的資源唯一標誌,例如:ETag: W/"2a3b-1602480f459",它根據資源內容而生成,可以精確感知資源的變動情況,即使多次更新,只要內容不變,Etag值也是不會變化的。瀏覽器下一次請求此資源時,request headers裏就會帶上一個值相同的名爲if-None-Match的字段用於服務器對此資源做對比,If-None-Match: W/"2a3b-1602480f459"

  • > Etag在感知文件變化上比Last-Modified更加準確,優先級也更高,不過Etag的生成會消耗掉部分服務器的性能,它可以作爲一種輔助協商緩存方式與前者相互配合使用。當EtagLast-Modified同時存在時,以Etag爲準。

Push Cache(優先級最低)


Push Cache 是指 HTTP2 在 server push 階段存在的緩存:

  • Push Cache 是緩存的最後一道防線。瀏覽器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的情況下才會去詢問 Push Cache。
  • Push Cache 是一種存在於會話階段的緩存,當 session 終止時,緩存也隨之釋放。
  • 不同的頁面只要共享了同一個 HTTP2 連接,那麼它們就可以共享同一個 Push Cache。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章