瀏覽器緩存機制有四個方面,它們按照獲取資源時請求的優先級依次排列以下:前端
1.Memory Cache數據庫
2.Service Worker Cache瀏覽器
3.HTTP Cache緩存
4.Push Cache性能優化
MemoryCache,是指存在內存中的緩存。從優先級上來講,它是瀏覽器最早嘗試去命中的一種緩存。從效率上來講,它是響應速度最快的一種緩存。服務器
不過當頁面關閉時,內存裏的數據也就沒有了。網絡
資源存不存內存,瀏覽器秉承的是「節約原則」。咱們發現,Base64 格式的圖片,幾乎永遠能夠被塞進 memory cache,這能夠視做瀏覽器爲節省渲染開銷的「自保行爲」;此外,體積不大的 JS、CSS 文件,也有較大地被寫入內存的概率——相比之下,較大的 JS、CSS 文件就沒有這個待遇了,內存資源是有限的,它們每每被直接甩進磁盤。session
Service Worker 是一種獨立於主線程以外的 Javascript 線程。它能夠幫咱們實現離線緩存、消息推送和網絡代理等功能。前端性能
一般咱們若是要使用 Service Worker 基本就是如下幾個步驟:性能
在頁面發起 http 請求時,service worker 能夠經過 fetch 事件攔截請求,而且給出本身的響應。
頁面和 serviceWorker 之間能夠經過 posetMessage() 方法發送消息,發送的消息能夠經過 message 事件接收到。
Service Worker 必須以 https 協議爲前提。
HTTP 緩存分爲強緩存和協商緩存。優先級較高的是強緩存,在命中強緩存失敗的狀況下,纔會走協商緩存。
強緩存指的是向瀏覽器緩存查找該請求的結果,並根據該結果的緩存規則來決定是否使用該緩存結果的過程
強緩存是利用http響應頭中的 Expires
和 Cache-Control
兩個字段來控制的。
實現強緩存,過去咱們一直用 expires
。
在服務器的響應頭裏,會將過時時間寫入 expires 字段:
那麼,當咱們試圖再次向服務器請求資源時,瀏覽器就會先對比本地時間和 expires 的時間,若是本地時間小於 expires 設定的過時時間,就直接去緩存中取這個資源。
不過expires依賴於本地時間,若是服務端和客戶端的時間設置不一樣,那麼expires 將沒法達到咱們的預期。
考慮到 expires 的侷限性,HTTP1.1 新增了 Cache-Control 字段來完成 expires 的任務。當 Cache-Control 與 expires 同時出現時,咱們以 Cache-Control 爲準。
Cache-Control 包含如下幾個值:
(1)max-age
cache-control: max-age=31536000
max-age 會等於一個時間長度(以秒爲單位)。在本例中,max-age 是 31536000 秒,它意味着該資源在 31536000 秒之內都是有效的,完美地規避了時間戳帶來的潛在問題。
在代理服務器中,咱們使用 s-maxage 來執行 max-age 的功能。
(2)public 與 private
若是咱們爲資源設置了 public,那麼它既能夠被瀏覽器緩存,也能夠被代理服務器緩存(也就是多個用戶能夠共享這個緩存);若是咱們設置了 private,則該資源只能被瀏覽器緩存。
private 爲默認值。
但多數狀況下,public 並不須要咱們手動設置,由於設置了 max-age 就表示響應是能夠緩存的。
(3)no-store 與 no-cache
若是咱們爲資源設置了 no-cache,瀏覽器會對響應進行緩存,可是須要到服務器去確認這個緩存是否能用。即走咱們下文即將講解的協商緩存的路線。
若是設置了 no-store ,全部內容都不會被緩存,即不使用強制緩存,也不使用協商緩存
協商緩存指的是強制緩存失效後,瀏覽器向服務器詢問緩存的相關信息,進而判斷是從新發起請求仍是從本地拿緩存的過程。
若是服務端提示緩存資源未改動(Not Modified),資源會被重定向到瀏覽器緩存,這種狀況下網絡請求對應的狀態碼是 304(以下圖)。
一樣,協商緩存的標識也是在響應報文的HTTP頭中和請求結果一塊兒返回給瀏覽器的,控制協商緩存的字段分別有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的優先級比Last-Modified / If-Modified-Since高。
若是咱們啓用了協商緩存,Last-Modified 會在首次請求時隨着響應頭返回:
Last-Modified: Fri, 27 Oct 2017 06:35:57 GMT
隨後咱們每次請求時,會帶上一個叫 If-Modified-Since 的時間戳字段,它的值正是上一次 response 返回給它的 last-modified 值:
If-Modified-Since: Fri, 27 Oct 2017 06:35:57 GMT
服務器接收到這個時間戳後,會比對該時間戳和資源在服務器上的最後修改時間是否一致,從而判斷資源是否發生了變化。若是發生了變化,就會返回一個完整的響應內容,並在響應頭中添加新的 Last-Modified 值;不然,返回如上圖的 304 響應,響應頭不會再添加 Last-Modified 字段。
Etag 是由服務器爲每一個資源生成的惟一的標識字符串,這個標識字符串是基於文件內容編碼的,只要文件內容不一樣,它們對應的 Etag 就是不一樣的。
當首次請求時,咱們會在響應頭裏獲取到一個最初的標識符字符串:
ETag: W/"2a3b-1602480f459"
那麼下一次請求時,請求頭裏就會帶上一個值相同的、名爲 if-None-Match 的字符串供服務端比對:
If-None-Match: W/"2a3b-1602480f459"
不過 Etag 的生成過程須要服務器額外付出開銷,會影響服務端的性能。
根據上文所說的 HTTP 緩存知識點,咱們在面對一個具體的緩存需求時,能夠根據下圖的路線來決策:
當咱們的資源內容不可複用時,直接爲 Cache-Control 設置 no-store,拒絕一切形式的緩存;不然考慮是否每次都須要向服務器進行緩存有效確認,若是須要,那麼設 Cache-Control 的值爲 no-cache;不然考慮該資源是否能夠被代理服務器緩存,根據其結果決定是設置爲 private 仍是 public;而後考慮該資源的過時時間,設置對應的 max-age 和 s-maxage 值;最後,配置協商緩存須要用到的 Etag、Last-Modified 等參數。
Push Cache 是指 HTTP2 在 server push 階段存在的緩存。
CDN (Content Delivery Network,即內容分發網絡)指的是一組分佈在各個地區的服務器。這些服務器存儲着數據的副本,所以服務器能夠根據哪些服務器與用戶距離最近,來知足數據的請求。 CDN 提供快速服務,較少受高流量影響。
CDN 的核心點有兩個,一個是緩存,一個是回源。
「緩存」就是說咱們把資源 copy 一份到 CDN 服務器上這個過程,「回源」就是說 CDN 發現本身沒有這個資源(通常是緩存的數據過時了),轉頭向根服務器(或者它的上層服務器)去要這個資源的過程。
CDN 每每被用來存放靜態資源,就是像 JS、CSS、圖片等不須要業務服務器進行計算即得的資源。
Web Storage 是 HTML5 專門爲瀏覽器存儲而提供的數據存儲機制。存儲容量能夠達到 5-10M 之間。它又分爲 Local Storage 與 Session Storage。
二者的區別在於生命週期與做用域的不一樣。
(1)存儲數據
localStorage.setItem('user_name', 'xiuyan') sessionStorage.setItem('key', 'value');
Web Storage只能存字符串。
(2)讀取數據
localStorage.getItem('user_name') var data = sessionStorage.getItem('key');
(3)刪除某一鍵名對應的數據
localStorage.removeItem('user_name') sessionStorage.removeItem('key');
(4)清除全部數據
localStorage.clear() sessionStorage.clear();
Local Storage 的特色之一是持久,有時咱們更傾向於用它來存儲一些內容穩定的資源。好比圖片內容豐富的電商網站會用它來存儲 Base64 格式的圖片字符串,有的網站還會用它存儲一些不常常更新的 CSS、JS 等靜態資源。
Session Storage 更適合用來存儲生命週期和它同步的會話級別的信息。這些信息只適用於當前會話,當你開啓新的會話時,它也須要相應的更新或釋放。好比微博的 Session Storage 就主要是存儲你本次會話的瀏覽足跡。
IndexDB 是一個運行在瀏覽器上的非關係型數據庫。