前端緩存總結

前端緩存總結

1 緩存

緩存從宏觀上分爲私有緩存和共享緩存,共享緩存就是那些能被各級代理緩存的緩存。私有緩存就是用戶專享的,各級代理不能緩存的緩存。

在這裏插入圖片描述
緩存從微觀上可以分爲以下幾類:

  • http緩存
  • 瀏覽器緩存
  • cdn緩存
  • 應用層緩存
  • 數據庫緩存

這裏主要對瀏覽器的緩存進行說明:
在這裏插入圖片描述

2 http緩存

http狀態碼:

    200 from memory cache
    不訪問服務器,直接讀緩存,從內存中讀取緩存。此時的數據時緩存到內存中的,當kill進程後,也就是瀏覽器關閉以後,數據將不存在。
    但是這種方式只能緩存派生資源。
    
    200 from disk cache
    
    不訪問服務器,直接讀緩存,從磁盤中讀取緩存,當kill進程時,數據還是存在。
    
    這種方式也只能緩存派生資源
    
    304 Not Modified
    
    訪問服務器,發現數據沒有更新,服務器返回此狀態碼(不返回資源)。然後從緩存中讀取數據。

哪些資源會被瀏覽器緩存?

首先這個資源是需要通過 GET 請求的,然後資源類型爲[腳本、樣式表、圖片、媒體、字體]是會緩存在 disk 中的,而其中的 [ 腳本、圖片、字體 ] 又是會緩存在 memory 中的。

2.1 三級緩存原理

  • 先查找內存,如果內存中存在,從內存中加載;
  • 如果內存中未查找到,選擇硬盤獲取,如果硬盤中有,從硬盤中加載;
  • 如果硬盤中未查找到,那就進行網絡請求;
  • 加載到的資源緩存到硬盤和內存;

HTTP緩存分爲強緩存和協議緩存,它們的區別如下:
在這裏插入圖片描述

2.2 強緩存

強緩存是利用http頭中的Expires和Cache-Control兩個字段來控制的,用來表示資源的緩存時間。強緩存中,普通刷新會忽略它,但不會清除它,需要強制刷新。瀏覽器強制刷新,請求會帶上Cache-Control:no-cache和Pragma:no-cache

  • 不會向服務器發送請求,直接從緩存中讀取資源
  • 請求返回200的狀態碼
  • 在chrome控制檯的network選項中可以看到size顯示from disk cache或from memory cache。

在這裏插入圖片描述

Expires和Cache-Control兩者對比:其實這兩者差別不大,區別就在於 Expires 是http1.0的產物,Cache-Control是http1.1的產物,兩者同時存在的話,Cache-Control優先級高於Expires

在這裏插入圖片描述

2.3 協商緩存

協商緩存就是強制緩存失效後,瀏覽器攜帶緩存標識向服務器發起請求,由服務器根據緩存標識決定是否使用緩存的過程

  • 協商緩存生效,返回304和Not Modified
    在這裏插入圖片描述

2.3.1 Last-Modified和If-Modified-Since

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

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

缺點:1、某些服務端不能獲取精確的修改時間 2、文件修改時間改了,但文件內容卻沒有變

2.3.2 ETag和If-None-Match

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

2.3.3 協商緩存兩種方式的對比

  • 首先在精確度上,Etag要優於Last-Modified,Last-Modified的時間單位是秒,如果某個文件在1秒內改變了多次,那麼他們的Last-Modified其實並沒有體現出來修改,但是Etag每次都會改變確保了精度;如果是負載均衡的服務器,各個服務器生成的Last-Modified也有可能不一致。
  • 性能上,Etag要遜於Last-Modified,畢竟Last-Modified只需要記錄時間,而Etag需要服務器通過算法來計算出一個hash值。
  • 優先級上,服務器校驗優先考慮Etag

3 緩存機制

appcache優先於強緩存,強制緩存優先於協商緩存進行,若強制緩存(Expires和Cache-Control)生效則直接使用緩存,若不生效則進行協商緩存(Last-Modified / If-Modified-Since和Etag / If-None-Match),協商緩存由服務器決定是否使用緩存,若協商緩存失效,那麼代表該請求的緩存失效,返回200,重新返回資源和緩存標識,再存入瀏覽器緩存中;生效則返回304,繼續使用緩存。具體流程看下圖:
在這裏插入圖片描述

不管是瀏覽器緩存,還是代理服務器緩存,CDN緩存都遵循客戶端與服務端之間的緩存機制

4、瀏覽器緩存+數據庫緩存

本地存儲主要有以下幾種,

  • localStorage
  • sessionStorage
  • cookie
  • WebSql
  • IndexDB

其中WebSql,IndexDB主要用在前端有大容量存儲需求的頁面上,例如,在線編輯瀏覽器或者網頁郵箱。他們都可以將數據存儲在瀏覽器,應該根據不同的場景進行使用。

4.1 Cookie

Cookie主要是由服務器生成,且前端也可以設置,保存在客戶端本地的一個文件,通過response響應頭的set-Cookie字段進行設置,且Cookie的內容自動在請求的時候被傳遞給服務器。如下:

[HTTP/1.1 200 OK]
Server:[bfe/1.0.8.18]
Etag:["58860415-98b"]
Cache-Control:[private, no-cache, no-store, proxy-revalidate, no-transform]
Connection:[Keep-Alive]
Set-Cookie:[BDORZ=27315; max-age=86400; domain=.baidu.com; path=/]
Pragma:[no-cache]
Last-Modified:[Mon, 23 Jan 2017 13:24:37 GMT]
Content-Length:[2443]
Date:[Mon, 09 Apr 2018 09:59:06 GMT]
Content-Type:[text/html]

Cookie包含的信息:
它可以記錄你的用戶ID、密碼、瀏覽過的網頁、停留的時間等信息。當你再次來到該網站時,網站通過讀取Cookies,得知你的相關信息,就可以做出相應的動作,如在頁面顯示歡迎你的標語,或者讓你不用輸入ID、密碼就直接登錄等等。一個網站只能讀取它自己放置的信息,不能讀取其他網站的Cookie文件。因此,Cookie文件還保存了host屬性,即網站的域名或ip。
這些屬性以名值對的方式進行保存,爲了安全,它的內容大多進行了加密處理。Cookie文件的命名格式是:用戶名@網站地址[數字].txt

Cookie的優點:

  • 給用戶更人性化的使用體驗,如記住“密碼功能”、老用戶登錄歡迎語
  • 彌補了HTTP無連接特性
  • 站點統計訪問人數的一個依據

Cookie的缺點:

  • 它無法解決多人共用一臺電腦的問題,帶來了不安全因素
  • Cookie文件容易被誤刪除
  • 一人使用多臺電腦
  • Cookies欺騙。修改host文件,可以非法訪問目標站點的Cookie
  • 容量有限制,不能超過4kb
  • 在請求頭上帶着數據安全性差

4.2 localStorage

localStorage主要是前端開發人員,在前端設置,一旦數據保存在本地後,就可以避免再向服務器請求數據,因此減少不必要的數據請求,減少數據在瀏覽器和服務器間不必要地來回傳遞。

可以長期存儲數據,沒有時間限制,一天,一年,兩年甚至更長,數據都可以使用。
localStorage中一般瀏覽器支持的是5M大小,這個在不同的瀏覽器中localStorage會有所不同

優點:

  • localStorage拓展了cookie的4k限制
  • localStorage可以將第一次請求的5M大小數據直接存儲到本地,相比於cookie可以節約帶寬
  • localStorage的使用也是遵循同源策略的,所以不同的網站直接是不能共用相同的localStorage

缺點:

  • 需要手動刪除,否則長期存在
  • 瀏覽器大小不一,版本的支持也不一樣
  • localStorage只支持string類型的存儲,JSON對象需要轉換
  • localStorage本質上是對字符串的讀取,如果存儲內容多的話會消耗內存空間,會導致頁面變卡

4.3 sessionStorage

sessionStorage主要是前端開發人員,在前端設置,sessionStorage(會話存儲),只有在瀏覽器被關閉之前使用,創建另一個頁面時同意可以使用,關閉瀏覽器之後數據就會消失

存儲上限限制:不同的瀏覽器存儲的上限也不一樣,但大多數瀏覽器把上限限制在5MB以下

4.4 websql

Web SQL 是在瀏覽器上模擬數據庫,可以使用JS來操作SQL完成對數據的讀寫。它使用 SQL 來操縱客戶端數據庫的 API,這些 API 是異步的,規範中使用的方言是SQLlite。數據庫還是在服務端,不建議使用,已廢棄

4.5 indexDB

隨着瀏覽器的功能不斷增強,越來越多的網站開始考慮,將大量數據儲存在客戶端,這樣可以減少從服務器獲取數據,直接從本地獲取數據。

現有的瀏覽器數據儲存方案,都不適合儲存大量數據:Cookie 的大小不超過4KB,且每次請求都會發送回服務器;LocalStorage 在 2.5MB 到 10MB 之間(各家瀏覽器不同),而且不提供搜索功能,不能建立自定義的索引。所以,需要一種新的解決方案,這就是 IndexedDB 誕生的背景。

通俗地說,IndexedDB 就是瀏覽器提供的本地數據庫,它可以被網頁腳本創建和操作。IndexedDB 允許儲存大量數據,提供查找接口,還能建立索引。這些都是 LocalStorage 所不具備的。就數據庫類型而言,IndexedDB 不屬於關係型數據庫(不支持 SQL 查詢語句),更接近 NoSQL 數據庫。

5 應用緩存–Application Cache

應用緩存全稱爲Offline Web Application,它的緩存內容被存在瀏覽器的Application Cache中。主要是通過manifest文件來標註要被緩存的靜態文件清單。但是在緩存靜態文件的同時,也會默認緩存html文件。這導致頁面的更新只能通過manifest文件中的版本號來決定。而且,即使我們更新了version,用戶的第一次訪問還是會訪問到老的頁面,只有下一次再訪問才能訪問到新的頁面。所以,應用緩存只適合那種常年不變化的靜態網站。

5.1 Manifest的特點

  • 離線瀏覽: 用戶可以在離線狀態下瀏覽網站內容。
  • 更快的速度: 因爲數據被存儲在本地,所以速度會更快.
  • 減輕服務器的負載: 瀏覽器只會下載在服務器上發生改變的資源。
  • 同源策略。
  • 缺點:兼容ie10以上

5.2 用法

創建一個和html同名的manifest文件,比如頁面爲index.html,那麼可以建一個index.manifest的文件,然後給index.html的html標籤添加如下屬性即可:

<html lang="en" manifest="index.manifest">

CACHE:(必須)
標識出哪些文件需要緩存,可以是相對路徑也可以是絕對路徑。

index.html
./static/js/index.js

NETWORK:(可選)
這一部分是要繞過緩存直接讀取的文件,可以使用通配符*。
下面的代碼 “login.html” 永遠不會被緩存,且離線時是不可用的:

NETWORK:login.html

可以使用星號來指示所有其他資源/文件都需要因特網連接:

NETWORK:* ###FALLBACK:(可選)

FALLBACK
指定了一個後備頁面,當資源無法訪問時,瀏覽器會使用該頁面。該段落的每條記錄都列出兩個 URI—第一個表示資源,第二個表示後備頁面。兩個 URI 都必須使用相對路徑並且與清單文件同源。可以使用通配符。

下面的例子中,如果無法建立因特網連接,則用 “404.html” 替代 /html5/ 目錄中的所有文件。

FALLBACK:/html5/ /404.html

下面的例子中,則用 “404.html” 替代所有文件。

FALLBACK:*.html /404.html

示例

CACHE MANIFEST
# v0.0.0
CACHE:
    css/editor.css
    css/icons.woff
    # js
    js/require.js
    js/main.js
    # html
    index.html
    demo.html
NETWORK:
*
FALLBACK:
*

如何更新緩存

  • 更新manifest文件

    給manifest添加或刪除文件,都可更新緩存,或者修改manifest文件中的版本號來更新緩存;
    
  • 通過javascript操作

if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.update();

```javascript
window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
     window.applicationCache .swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);
  • 清除瀏覽器緩存
    用戶手動清除瀏覽器緩存數據

注意事項

  • application cache會默認緩存當前頁面!!!就算我們有如下設置:NETWORK:*.
  • 必須爲UTF-8編碼.
  • 第一行必須爲CACHE MANIFEST
  • 需要添加 MIME TYPE:text/cache-manifest
  • 當更新後,第一次訪問並不是蛭新的頁面,刷新後纔會更新。 如果manifest文件,或者內部列舉的某一個文件不能正常下載,整個更新過程都將失敗,瀏覽器繼續全部使用老的緩存。
  • 瀏覽器對緩存數據的容量限制可能不太一樣(某些瀏覽器設置的限制是每個站點 5MB)。
  • 當一個資源被緩存後,該瀏覽器直接請求這個絕對路徑也會訪問緩存中的資源。
  • 站點中的其他頁面即使沒有設置manifest屬性,請求的資源如果在緩存中也從緩存中訪問。
  • 當manifest文件發生改變時,資源請求本身也會觸發更新。

6 瀏覽器緩存更新或清除方案

6.1 meta方法

//不緩存
<META HTTP-EQUIV="pragma" CONTENT="no-cache"> 
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> 
<META HTTP-EQUIV="expires" CONTENT="0">

6.2 清理form表單的臨時緩存

<body onLoad="javascript:document.yourFormName.reset()">

其實form表單的緩存對於我們書寫還是有幫助的,一般情況不建議清理,但是有時候爲了安全問題等,需要清理一下!

6.3 ajax清除瀏覽器緩存

方式一:用ajax請求服務器最新文件,並加上請求頭If-Modified-Since和Cache-Control,如下:

 $.ajax({
     url:'www.haorooms.com',
     dataType:'json',
     data:{},
     beforeSend :function(xmlHttp){ 
        xmlHttp.setRequestHeader("If-Modified-Since","0"); 
        xmlHttp.setRequestHeader("Cache-Control","no-cache");
     },
     success:function(response){
         //操作
     }
     async:false
  });

方法二,直接用cache:false,

   $.ajax({
     url:'www.haorooms.com',
     dataType:'json',
     data:{},
     cache:false, 
     ifModified :true ,

     success:function(response){
         //操作
     }
     async:false
  });

方法三:用隨機數,隨機數也是避免緩存的一種很不錯的方法!

URL 參數後加上 "?ran=" + Math.random(); //當然這裏參數 ran可以任意取了

方法四:用隨機時間,和隨機數一樣。

URL 參數後加上 "?timestamp=" + new Date().getTime(); 

6.4 靜態資源更新緩存

在資源文件名後增加版本號,可用隨機數或隨機時間做版本號,利用文件辨識符的不一致,獲取服務器最新資源;

<script src="js/app.js?version=new Date().getTime()"></script> "?timestamp=" + new Date().getTime(); 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章