簡單來說考廉,瀏覽器緩存就是把一個已經(jīng)請求過的資源拷貝一份存儲起來茉继,當(dāng)下次需要該資源時(shí)翼闹,瀏覽器會根據(jù)緩存機(jī)制決定直接使用緩存資源還是再次向服務(wù)器發(fā)送請求丁寄。
如下圖所示是我在第二次打開某個網(wǎng)頁時(shí)的資源請求圖柑营,可以看出里面大部分資源是從瀏覽器直接讀取了緩存屈雄。
那么瀏覽器緩存究竟有什么作用呢?
瀏覽器緩存最主要的作用是減少網(wǎng)絡(luò)傳輸?shù)膿p耗以及降低服務(wù)器壓力官套。
接下來我將通過以下幾個部分來探討瀏覽器緩存機(jī)制:
- 緩存位置
- 緩存策略
緩存位置
瀏覽器緩存位置分為四種酒奶,其優(yōu)先級順序如下:
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
當(dāng)上述四個緩存位置中的緩存都沒有命中時(shí)蚁孔,則會向服務(wù)器發(fā)起請求。
Service Worker
Service Worker 是一個注冊在指定源和路徑下的事件驅(qū)動 worker讥蟆。它采用 JavaScript 控制關(guān)聯(lián)的頁面或者網(wǎng)站遍膜,攔截并修改訪問和資源請求,細(xì)粒度地緩存資源转绷。
我們可以通過谷歌開發(fā)者工具中的 Application -> Service Workers 查看當(dāng)前緩存的資源徊哑。
Memory Cache
Memory Cache 即內(nèi)存中的緩存,其特點(diǎn)是容量小质况、讀取高效愕宋、持續(xù)性短,會隨著進(jìn)程的釋放而釋放结榄。
所以中贝,在內(nèi)存使用率低、緩存小尺寸資源時(shí)臼朗,會以 Memory Cache 為優(yōu)先邻寿,否則使用 Disk Cache。
Disk Cache
Disk Cache 即磁盤中的緩存视哑,其特點(diǎn)是容量大绣否、讀取緩慢、持續(xù)性長挡毅,任何資源都能存儲到磁盤中蒜撮。
所以,在內(nèi)存使用率高跪呈、緩存大尺寸資源時(shí)段磨,會以 Disk Cache 為優(yōu)先。
Push Cache
Push Cache 是 HTTP 2.0 中的內(nèi)容耗绿,其緩存時(shí)間也很短暫苹支,只在會話(Session)中存在,一旦會話結(jié)束就被釋放误阻。
緩存策略
瀏覽器每次在向服務(wù)器發(fā)起 HTTP 請求獲得資源后沐序,可能會根據(jù)不同情況(可能是代碼控制如 Service Worker、Push Cache堕绩,也可能是根據(jù) HTTP Header 的緩存標(biāo)識字段)將資源緩存起來策幼。
瀏覽器緩存策略分為強(qiáng)制緩存和協(xié)商緩存,其是通過設(shè)置 HTTP Header 來實(shí)現(xiàn)的奴紧。
強(qiáng)制緩存
當(dāng)瀏覽器發(fā)起 HTTP 請求時(shí)特姐,會依次查找上述緩存位置中是否存在緩存資源并通過緩存標(biāo)識字段 Expires 或 Cache-Control 來驗(yàn)證緩存資源是否過期。
Expires 是服務(wù)器端在響應(yīng)請求時(shí)用來規(guī)定資源的失效時(shí)間黍氮。
Cache-Control 是服務(wù)器端在響應(yīng)請求時(shí)用來規(guī)定資源是否需要被瀏覽器緩存以及緩存的有效時(shí)間等唐含。
Cache-Control 主要取值如下:
Expires 是 HTTP 1.0 的字段浅浮,而 Cache-Control 是 HTTP 1.1 的字段,當(dāng) Expires 與 Cache-Control 同時(shí)存在時(shí)捷枯,Cache-Control 的優(yōu)先級要高于 Expires滚秩。
若是命中緩存(即存在緩存資源并且緩存資源未過期),則瀏覽器響應(yīng) HTTP Status Code 200淮捆,并直接使用緩存資源作為返回結(jié)果郁油,不需要發(fā)起 HTTP 請求;若是存在緩存資源但緩存資源已過期攀痊,則進(jìn)入協(xié)商緩存桐腌。
協(xié)商緩存
與協(xié)商緩存相關(guān)的緩存標(biāo)識字段是 Last-Modified 和 Etag。
Last-Modified 是服務(wù)器端在響應(yīng)請求時(shí)用來說明資源的最后修改時(shí)間苟径。與之對應(yīng)的是 If-Modified-Since 字段案站,在協(xié)商緩存過程中,瀏覽器發(fā)送的 HTTP 請求中 Header 中會帶上 If-Modified-Since 字段棘街,值為緩存資源 Last-Modified 屬性的值蟆盐。
當(dāng)服務(wù)器端接收到帶有 If-Modified-Since 的請求時(shí),則會將 If-Modified-Since 的值與被請求資源的最后修改時(shí)間做對比遭殉。如果相同舱禽,說明資源沒有新的修改,則響應(yīng) HTTP Status Code 304恩沽,瀏覽器會繼續(xù)使用緩存資源;如果最后修改時(shí)間比較新翔始,則說明資源被修改過罗心,則響應(yīng) HTTP Status Code 200,并返回最新的資源城瞎。
Etag 是服務(wù)器端在響應(yīng)請求時(shí)用來說明資源在服務(wù)器端的唯一標(biāo)識渤闷。與之對應(yīng)的是 If-None-Match 字段,在協(xié)商緩存過程中脖镀,瀏覽器發(fā)送的 HTTP 請求中 Header 中會帶上 If-None-Match 字段飒箭,值為該緩存資源 Etag 屬性的值。
當(dāng)服務(wù)器端接收到帶有 If-None-Match 的請求時(shí)蜒灰,則會將 If-None-Match 的值與被請求資源的唯一標(biāo)識做對比弦蹂。如果相同,說明資源沒有新的修改强窖,則響應(yīng) HTTP Status Code 304凸椿,瀏覽器會繼續(xù)使用緩存資源;如果不同翅溺,則說明資源被修改過脑漫,則響應(yīng) HTTP Status Code 200髓抑,并返回最新的資源。
Last-Modified 是 HTTP 1.0 的字段优幸,而 Etag 是 HTTP 1.1 的字段吨拍,當(dāng) Last-Modified 與 Etag 同時(shí)存在時(shí),Etag 的優(yōu)先級要高于 Last-Modified网杆。
Etag 的出現(xiàn)主要是為了解決 Last-Modified 存在的問題:
- Last-Modified 標(biāo)注的最后修改只能精確到秒級羹饰,如果某些文件在 1 秒鐘以內(nèi)被修改多次的話,它將不能準(zhǔn)確標(biāo)注文件的最后修改時(shí)間跛璧;
- 如果本地打開緩存文件严里,即使沒有對文件進(jìn)行修改,但 Last-Modified 卻改變了追城,導(dǎo)致文件沒法使用緩存刹碾;
下面用一張流程圖來完整說明當(dāng)瀏覽器發(fā)起 HTTP 請求時(shí)緩存機(jī)制的過程: