瀏覽器緩存機制的深入解析

一、簡介瀏覽器緩存

瀏覽器緩存就是把一個已經(jīng)請求過的Web資源(如html頁面,圖片,js,數(shù)據(jù)等)拷貝一份副本儲存在瀏覽器中。緩存會根據(jù)進來的請求保存輸出內(nèi)容的副本。當下一個請求來到的時候,如果是相同的URL,緩存會根據(jù)緩存機制決定是直接使用副本響應訪問請求,還是向服務器再次發(fā)送請求,從而返回新的數(shù)據(jù)。

緩存的優(yōu)點:

  • 優(yōu)秀的緩存策略可以縮短網(wǎng)頁請求資源的距離,減少延遲。
  • 緩存文件可以重復利用。
  • 減少帶寬資源浪費,降低網(wǎng)絡負荷。
  • 加快頁面渲染速度。

常規(guī)數(shù)據(jù)請求主要分為三步:HTTP請求、后端處理、瀏覽器響應三個步驟,瀏覽器緩存可以幫助我們在第一和第三步驟中優(yōu)化性能。比如說直接使用緩存而不發(fā)起請求,或者發(fā)起了請求但后端存儲的數(shù)據(jù)和前端一致,那么就沒有必要再將數(shù)據(jù)回傳回來,這樣就減少了響應數(shù)據(jù)。

理解了緩存和緩存策略的優(yōu)點,接下來我們帶著以下幾個問題來深入講解緩存機制。

  1. 緩存的流程
  2. 緩存的儲存位置
  3. 緩存的分類以及它們之間的異同、優(yōu)劣。

二、瀏覽器緩存的流程

HTTP請求就是客戶端和服務端之間應答的模式,當瀏覽器發(fā)起請求到服務端處理,服務端響應,再到瀏覽器接受數(shù)據(jù),渲染頁面,這其中數(shù)據(jù)是如何被瀏覽器緩存以及之后如何被瀏覽器再次使用的,請先看下圖。


緩存流程.png

通過上圖容易理解

  • 瀏覽器每次發(fā)起請求,都會先在瀏覽器緩存中查找該請求的結果以及緩存標識
  • 瀏覽器每次拿到服務器返回的請求結果都會將該結果和緩存標識存入瀏覽器緩存中
    以上兩點解釋了緩存中數(shù)據(jù)的儲存和讀取過程,但是瀏覽器緩存的具體位置在哪里?

三、瀏覽器緩存位置

查看瀏覽器緩存

image.png

緩存位置主要有以下四種

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache

Service Worker

瀏覽器緩存本質(zhì)還是由服務器控制,但是Service Workder則完全由前端瀏覽器自己控制,可能有人會說,瀏覽器還可以使用Local Storage或者Session Storage來存儲一些數(shù)據(jù),但這種方法缺少很多關鍵的瀏覽器基礎設施,比如異步存儲、靜態(tài)資源存儲、URL匹配、請求攔截等功能。而Service Worker的出現(xiàn)填補了這些基礎設施缺少的問題。

需要指出的是,Service Worker并非專門為緩存而設計,它還可以解決Web應用推送、后臺長計算等問題。Service Worker 是運行在瀏覽器背后的獨立線程,相對于頁面主線程是一個全新的JS線程,主Javascript線程是負責DOM的線程,而service worker線程被設計成無法訪問DOM。從事前端開發(fā)的都知道,如果同時存在多個UI線程,會出現(xiàn)操作失控,控制紊亂的效果,舉個簡單的例子,如果一個線程將DOM刪除,另一個線程對DOM進行點擊等操作,這就出行混亂的現(xiàn)象,所以只能有一個UI線程,所以Service Worder是一個不能對DOM操作的線程。

Service Worder緩存
Service Worker緩存關鍵在于監(jiān)聽Fetch事件和管理Cache資源,不過在這之間需要注冊激活,這里注冊激活流程不詳細講解,它能攔截所有的請求(通過監(jiān)聽fetch事件,任何對網(wǎng)絡資源的請求都會觸發(fā)該事件),并內(nèi)置了一個完全異步的存儲系統(tǒng)(Caches屬性,完全異步并能存儲全部種類的網(wǎng)絡資源),這是它能精細化控制緩存的關鍵。

Service Worker的出現(xiàn)并不是單純的為解決精細化控制瀏覽器緩存問題的。它能充當代理服務器這一能力(通過攔截所有請求實現(xiàn)),能夠?qū)崿F(xiàn)HTTP緩存無法實現(xiàn)的功能:離線緩存。因為在HTTP緩存策略下,如果一個資源過了服務器規(guī)定的到期時間,則必須要發(fā)起請求,一旦網(wǎng)絡連接有問題,整個網(wǎng)站就會出現(xiàn)功能問題。而在Service Worker控制下的緩存,能夠在代碼中發(fā)現(xiàn)網(wǎng)絡連接問題并直接返回緩存的資源。
由于Service Worker能攔截HTTP請求,充當代理服務器這個功能,所以必須運行咋HTTPS的Origin中,localhost也被認為是安全的,可以用于開發(fā)調(diào)試。

Memory Cache(200 from memory cache)

Memory Cache 也就是內(nèi)存中的緩存,主要包含的是當前中頁面中已經(jīng)抓取到的資源,例如頁面上已經(jīng)下載的樣式、腳本、圖片等。讀取內(nèi)存中的數(shù)據(jù)肯定比磁盤快,內(nèi)存緩存雖然讀取高效,可是緩存持續(xù)性很短,會隨著進程的釋放而釋放。 一旦我們關閉 Tab 頁面,內(nèi)存中的緩存也就被釋放了。
需要注意的事情是,內(nèi)存緩存在緩存資源時并不關心返回資源的HTTP緩存頭Cache-Control是什么值,同時資源的匹配也并非僅僅是對URL做匹配,還可能會對Content-Type,CORS等其他特征做校驗。

Disk Cache(200 from disk cache)

Disk Cache 也就是存儲在硬盤中的緩存,讀取速度慢點,但是什么都能存儲到磁盤中,比之 Memory Cache 勝在容量和存儲時效性上。
在所有瀏覽器緩存中,Disk Cache 覆蓋面基本是最大的。它會根據(jù) HTTP Herder 中的字段判斷哪些資源需要緩存,哪些資源可以不請求直接使用,哪些資源已經(jīng)過期需要重新請求。并且即使在跨站點的情況下,相同地址的資源一旦被硬盤緩存下來,就不會再次去請求數(shù)據(jù)。絕大部分的緩存都來自 Disk Cache。

Push Cache

Push Cache(推送緩存)是 HTTP/2 中的內(nèi)容,當以上三種緩存都沒有命中時,它才會被使用。它只在會話(Session)中存在,一旦會話結束就被釋放,并且緩存時間也很短暫,在Chrome瀏覽器中只有5分鐘左右,同時它也并非嚴格執(zhí)行HTTP頭中的緩存指令。


image.png

原理:圖中簡化了瀏覽器和服務器的交互過程,橫軸代表時間軸,每個虛線區(qū)間是1個RTT。紅色豎線表示DOM 加載完成的時間。從圖中可知,雖然存在并發(fā)傳輸, 但主頁index.html和依賴的資源common.css、0684a8bf.css、comb.nowrap.0b772fee.js等總體上是順序的,等待資源響應的時間減慢了主頁面加載速度。

如果服務端接收到客戶端主請求,能夠“預測”主請求的依賴資源,在響應主請求的同時,主動并發(fā)推送依賴資源至客戶端。客戶端解析主請求響應后,可以”無延時”從本地緩存獲取依賴資源, 減少訪問延時, 提高訪問體驗,也加大了鏈路的并發(fā)能力。Server Push正是基于此原理來提高網(wǎng)絡體驗。


image.png

圖3說明了若采用服務端推送的功能,則JS/CSS資源基本可以和HTML資源同步到達,瀏覽器可以“無延時”獲取JS/CSS資源,客戶端的延時最多可以減少一個RTT。

如果以上四種緩存都沒有命中的話,那么只能發(fā)起請求來獲取資源了。

四、緩存的分類以及它們之間的區(qū)別

HTTP請求根據(jù)緩存類型主要分為兩種緩存方式:強緩存和協(xié)商緩存

強緩存

強緩存:不會向服務器發(fā)送請求,直接從緩存中讀取資源,在chrome控制臺的Network選項中可以看到該請求返回200的狀態(tài)碼,并且Size顯示from disk cache或from memory cache。強緩存可以通過設置兩種 HTTP Header 實現(xiàn):Expires 和 Cache-Control

1. Cache-Control
在HTTP/1.1中,Cache-Control是最重要的規(guī)則,主要用于控制網(wǎng)頁緩存。比如當Cache-Control:max-age=300時,則代表在這個請求正確返回時間(瀏覽器也會記錄下來)的5分鐘內(nèi)再次加載資源,就會命中強緩存。
Cache-Control 可以在請求頭或者響應頭中設置,并且可以組合使用多種指令:

Cache-Control.png

public:所有內(nèi)容都將被緩存(客戶端和代理服務器都可緩存)。具體來說響應可被任何中間節(jié)點緩存,如 Browser <-- proxy1 <-- proxy2 <-- Server,中間的proxy可以緩存資源,比如下次再請求同一資源proxy1直接把自己緩存的東西給 Browser 而不再向proxy2要。

private:所有內(nèi)容只有客戶端可以緩存,Cache-Control的默認取值。具體來說,表示中間節(jié)點不允許緩存,對于Browser <-- proxy1 <-- proxy2 <-- Server,proxy 會老老實實把Server 返回的數(shù)據(jù)發(fā)送給proxy1,自己不緩存任何數(shù)據(jù)。當下次Browser再次請求時proxy會做好請求轉(zhuǎn)發(fā)而不是自作主張給自己緩存的數(shù)據(jù)。

no-cache:客戶端緩存內(nèi)容,是否使用緩存則需要經(jīng)過協(xié)商緩存來驗證決定。表示不使用 Cache-Control的緩存控制方式做前置驗證,而是使用 Etag 或者Last-Modified字段來控制緩存。需要注意的是,no-cache這個名字有一點誤導。設置了no-cache之后,并不是說瀏覽器就不再緩存數(shù)據(jù),只是瀏覽器在使用緩存數(shù)據(jù)時,需要先確認一下數(shù)據(jù)是否還跟服務器保持一致。

no-store:所有內(nèi)容都不會被緩存,即不使用強制緩存,也不使用協(xié)商緩存

max-age:max-age=xxx (xxx is numeric)表示緩存內(nèi)容將在xxx秒后失效

s-maxage(單位為s):同max-age作用一樣,只在代理服務器中生效(比如CDN緩存)。比如當s-maxage=60時,在這60秒中,即使更新了CDN的內(nèi)容,瀏覽器也不會進行請求。max-age用于普通緩存,而s-maxage用于代理緩存。s-maxage的優(yōu)先級高于max-age。如果存在s-maxage,則會覆蓋掉max-age和Expires header。

max-stale:能容忍的最大過期時間。max-stale指令標示了客戶端愿意接收一個已經(jīng)過期了的響應。如果指定了max-stale的值,則最大容忍時間為對應的秒數(shù)。如果沒有指定,那么說明瀏覽器愿意接收任何age的響應(age表示響應由源站生成或確認的時間與當前時間的差值)。

min-fresh:能夠容忍的最小新鮮度。min-fresh標示了客戶端不愿意接受新鮮度不多于當前的age加上min-fresh設定的時間之和的響應。

image.png

2. Expires
緩存過期時間,用來指定資源到期的時間,是服務器端的具體的時間點。也就是說,Expires=max-age + 請求時間,需要和Last-modified結合使用。Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數(shù)據(jù),而無需再次請求。
Expires 是 HTTP/1 的產(chǎn)物,受限于本地時間,如果修改了本地時間,可能會造成緩存失效。Expires: Wed, 22 Oct 2018 08:41:00 GMT表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT 后過期,需要再次請求。
Expires其實是過時的產(chǎn)物,現(xiàn)階段它的存在只是一種兼容性的寫法,如果同時存在Cache-Control和Expires,Cache-Control的優(yōu)先級更高。

強緩存判斷是否緩存的依據(jù)來自于是否超出某個時間或者某個時間段,而不關心服務器端文件是否已經(jīng)更新,這可能會導致加載文件不是服務器端最新的內(nèi)容,那我們?nèi)绾潍@知服務器端內(nèi)容是否已經(jīng)發(fā)生了更新呢?此時我們需要用到協(xié)商緩存策略。

協(xié)商緩存

協(xié)商緩存就是強制緩存失效后,瀏覽器攜帶緩存標識向服務器發(fā)起請求,由服務器根據(jù)緩存標識決定是否使用緩存的過程,主要有以下兩種類型:Last-Modified 和 ETag

  • 協(xié)商緩存生效,返回304和Not Modified


    image.png
  • 協(xié)商緩存失效,返回200和請求結果


    image.png

1. Last-Modified和If-Modified-Since
瀏覽器在第一次訪問資源時,服務器返回資源的同時,在response header中添加 Last-Modified的header,值是這個資源在服務器上的最后修改時間,瀏覽器接收后緩存文件和header;

Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT

瀏覽器下一次請求這個資源,瀏覽器檢測到有 Last-Modified這個header,于是請求添加If-Modified-Since這個header,值就是Last-Modified中的值;服務器再次收到這個資源請求,會根據(jù) If-Modified-Since 中的值與服務器中這個資源的最后修改時間對比,如果沒有變化,返回304和空的響應體,直接從緩存讀取,如果If-Modified-Since的時間小于服務器中這個資源的最后修改時間,說明文件有更新,于是返回新的資源文件和200。


image.png

如果本地打開緩存文件,即使沒有對文件進行修改,但還是會造成 Last-Modified 被修改,服務端不能命中緩存導致發(fā)送相同的資源
因為 Last-Modified 只能以秒計時,如果在不可感知的時間內(nèi)修改完成文件,那么服務端會認為資源還是命中了,不會返回正確的資源

既然根據(jù)文件修改時間來決定是否緩存尚有不足,能否可以直接根據(jù)文件內(nèi)容是否修改來決定緩存策略?所以在 HTTP / 1.1 出現(xiàn)了 ETag 和If-None-Match

2. ETag 和If-None-Match
Etag是服務器響應請求時,返回當前資源文件的一個唯一標識(由服務器生成),只要資源有變化,Etag就會重新生成。瀏覽器在下一次加載資源向服務器發(fā)送請求時,會將上一次返回的Etag值放到request header里的If-None-Match里,服務器只需要比較客戶端傳來的If-None-Match跟自己服務器上該資源的ETag是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。如果服務器發(fā)現(xiàn)ETag匹配不上,那么直接以常規(guī)GET 200回包形式將新的資源(當然也包括了新的ETag)發(fā)給客戶端;如果ETag是一致的,則直接返回304知會客戶端直接使用本地緩存即可。

image.png

3. 兩者的區(qū)別

  • 首先在精確度上,Etag要優(yōu)于Last-Modified。

Last-Modified的時間單位是秒,如果某個文件在1秒內(nèi)改變了多次,那么他們的Last-Modified其實并沒有體現(xiàn)出來修改,但是Etag每次都會改變確保了精度;如果是負載均衡的服務器,各個服務器生成的Last-Modified也有可能不一致。

  • 第二在性能上,Etag要遜于Last-Modified,畢竟Last-Modified只需要記錄時間,而Etag需要服務器通過算法來計算出一個hash值(記錄內(nèi)容是否發(fā)生變化)。
  • 第三在優(yōu)先級上,服務器校驗優(yōu)先考慮Etag

五、實際應用

1.頻繁變動的資源

Cache-Control: no-cache

對于頻繁變動的資源,首先需要使用Cache-Control: no-cache 使瀏覽器每次都請求服務器,然后配合 ETag 或者 Last-Modified 來驗證資源是否有效。這樣的做法雖然不能節(jié)省請求數(shù)量,但是能顯著減少響應數(shù)據(jù)大小。

2.不常變化的資源

Cache-Control: max-age=31536000

通常在處理這類資源時,給它們的 Cache-Control 配置一個很大的 max-age=31536000 (一年),這樣瀏覽器之后請求相同的 URL 會命中強制緩存。而為了解決更新的問題,就需要在文件名(或者路徑)中添加 hash, 版本號等動態(tài)字符,之后更改動態(tài)字符,從而達到更新URL 的目的,更新強制緩存的有效期。

六、用戶操作如何觸發(fā)瀏覽器緩存

  • 打開網(wǎng)頁,地址欄輸入地址: 查找 disk cache 中是否有匹配。如有則使用;如沒有則發(fā)送網(wǎng)絡請求。
  • 普通刷新 (F5):因為 TAB 并沒有關閉,因此 memory cache 是可用的,會被優(yōu)先使用(如果匹配的話)。其次才是 disk cache。
  • 強制刷新 (Ctrl + F5):瀏覽器不使用緩存,因此發(fā)送的請求頭部均帶有 Cache-control: no-cache(為了兼容,還帶了 Pragma: no-cache),服務器直接返回 200 和最新內(nèi)容。

簡單理解:

打開新頁面訪問-> 
200(新數(shù)據(jù),并緩存) -> 
退出瀏覽器再進來-> 
200(from disk cache) -> 
普通刷新 -> 
200(from memory cache)

七、總結

強緩存優(yōu)先于協(xié)商緩存,若強制緩存(Expires和Cache-Control)生效則直接使用緩存,若不生效則進行協(xié)商緩存(Last-Modified / If-Modified-Since和Etag / If-None-Match),協(xié)商緩存由服務器決定是否使用緩存,若協(xié)商緩存失效,那么代表該請求的緩存失效,返回200,重新返回資源和緩存標識,再存入瀏覽器緩存中;生效則返回304,繼續(xù)使用緩存。具體流程圖如下:

image.png

看到這里,不知道你是否存在這樣一個疑問:如果什么緩存策略都沒設置,那么瀏覽器會怎么處理?
對于這種情況,瀏覽器會采用一個啟發(fā)式的算法,通常會取響應頭中的 Date 減去 Last-Modified 值的 10% 作為緩存時間。

參考文章:深入理解瀏覽器的緩存機制

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內(nèi)容

  • 一、前言 緩存可以說是性能優(yōu)化中簡單高效的一種優(yōu)化方式了。一個優(yōu)秀的緩存策略可以縮短網(wǎng)頁請求資源的距離,減少延遲,...
    浪里行舟閱讀 206,730評論 46 521
  • 來源: https://www.infoq.cn/article/8VU-VCrhoxducaFPrNOL 一、前...
    AAA前端閱讀 270評論 0 2
  • 瀏覽器對于請求資源, 流程如圖所示: 可以看到瀏覽器的緩存機制分為兩個部分: 1、當前緩存是否過期? 2、服務器中...
    zhoulujun閱讀 1,222評論 0 3
  • 一、前言 緩存可以說是性能優(yōu)化中簡單高效的一種優(yōu)化方式了。一個優(yōu)秀的緩存策略可以縮短網(wǎng)頁請求資源的距離,減少延遲,...
    沉落的星星閱讀 391評論 0 0
  • 五月,油菜進入收割季節(jié),安鄉(xiāng)農(nóng)村農(nóng)戶紛紛抓住當前有利時機下田收割油菜,田間地頭呈現(xiàn)出一派收割油菜的繁忙場景。
    測繪兵閱讀 864評論 0 1