前端緩存總結
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();