浏覽器緩存是浏覽器端儲存資料用于快速讀取或避免重複資源請求的優化機制,有效的緩存使用可以避免重複的網絡請求和浏覽器快速地讀取本地資料,整體上加速網頁展示給使用者。浏覽器端緩存的機制種類較多,總體歸納為九種,這裡詳細分析下這九種緩存機制的原理和使用場景。打開浏覽器的調試模式->resources左側就有浏覽器的8種緩存機制。
一、http緩存
http緩存是基于http協定的浏覽器檔案級緩存機制。即針對檔案的重複請求情況下,浏覽器可以根據協定頭判斷從伺服器端請求檔案還是從本地讀取檔案,chrome控制台下的frames即展示的是浏覽器的http檔案級緩存。以下是浏覽器緩存的整個機制流程。主要是針對重複的http請求,在有緩存的情況下判斷過程主要分3步:
◆判斷expires,如果未過期,直接讀取http緩存檔案,不發http請求,否則進入下一步。
◆判斷是否含有etag,有則帶上if-none-match發送請求,未修改傳回304,修改傳回200,否則進入下一步。
◆判斷是否含有last-modified,有則帶上if-modified-since發送請求,無效傳回200,有效傳回304,否則直接向伺服器請求。
如果通過etag和last-modified判斷,即使傳回304有至少有一次http請求,隻不過傳回的是304的傳回内容,而不是檔案内容。是以合理設計實作expires參數可以減少較多的浏覽器請求。
二、websql
websql這種方式隻有較新的chrome浏覽器支援,并以一個獨立規範形式出現,主要有以下特點:
◆web sql 資料庫api 實際上不是html5規範的組成部分;
◆在html5之前就已經存在了,是單獨的規範;
◆它是将資料以資料庫的形式存儲在用戶端,根據需求去讀取;
◆跟storage的差別是: storage和cookie都是以鍵值對的形式存在的;
◆web sql 更友善于檢索,允許sql語句查詢;
◆讓浏覽器實作小型資料庫存儲功能;
◆這個資料庫是內建在浏覽器裡面的,目前主流浏覽器基本都已支援;
websql api主要包含三個核心方法:
◆opendatabase : 這個方法使用現有資料庫或建立新資料庫建立資料庫對象。
◆transaction : 這個方法允許我們根據情況控制事務送出或復原。
◆executesql : 這個方法用于執行真實的sql查詢。
opendatabase方法可以打開已經存在的資料庫,不存在則建立:
var db = opendatabase('mydatabase', '2.0', my db',2*1024);
opendatabasek中五個參數分别為:資料庫名、版本号、描述、資料庫大小、建立回調。建立回調沒有也可以建立資料庫。
database.transaction() 函數用來查詢,executesql()用于執行sql語句。
例如在mydatabase資料庫中建立表t1:
var db = opendatabase(' mydatabase ', '1.0', 'test db', 2 * 1024 * 1024);
db.transaction(function(tx){
tx.executesql('create table if not exists t1 (id unique, log)');
});
插入操作:
var db = opendatabase('mydatabase', '2.0', my db', 2 * 1024);
db.transaction(function (tx) {
tx.executesql('insert into t1 (id, log) values (1, "foobar")');
tx.executesql('insert into t1 (id, log) values (2, "logmsg")');
在插入新記錄時,我們還可以傳遞動态值,如:
var db = opendatabase(' mydatabase ', '2.0', 'my db', 2 * 1024);
tx.executesql('create table if not exists t1 (id unique, log)');
tx.executesql('insert into t1 (id,log) values (?, ?'), [e_id, e_log]; //e_id和e_log是外部變量
讀操作,如果要讀取已經存在的記錄,我們使用一個回調捕獲結果:
var db = opendatabase(mydatabase, '2.0', 'my db', 2*1024);
});
tx.executesql('select * from t1, [], function (tx, results) {
var len = results.rows.length, i;
msg = "<p>found rows: " + len + "</p>";
document.queryselector('#status').innerhtml += msg;
for (i = 0; i < len; i++){
alert(results.rows.item(i).log );
}
}, null);
三、indexdb
indexeddb 是一個為了能夠在用戶端存儲可觀數量的結構化資料,并且在這些資料上使用索引進行高性能檢索的 api。雖然 dom 存儲,對于存儲少量資料是非常有用的,但是它對大量結構化資料的存儲就顯得力不從心了。indexeddb 則提供了這樣的一個解決方案。
indexeddb 分别為同步和異步通路提供了單獨的 api 。同步 api 本來是要用于僅供 web workers 内部使用,但是還沒有被任何浏覽器所實作。異步 api 在 web workers 内部和外部都可以使用,另外浏覽器可能對indexdb有50m大小的限制,一般使用者儲存大量使用者資料并要求資料之間有搜尋需要的場景。
異步api
異步 api 方法調用完後會立即傳回,而不會阻塞調用線程。要異步通路資料庫,要調用 window 對象 indexeddb 屬性的 open() 方法。該方法傳回一個 idbrequest 對象 (idbopendbrequest);異步操作通過在 idbrequest 對象上觸發事件來和調用程式進行通信。
◆idbfactory 提供了對資料庫的通路。這是由全局對象 indexeddb 實作的接口,因而也是該 api 的入口。
◆idbcursor 周遊對象存儲空間和索引。
◆idbcursorwithvalue 周遊對象存儲空間和索引并傳回遊标的目前值。
◆idbdatabase 表示到資料庫的連接配接。隻能通過這個連接配接來拿到一個資料庫事務。
◆idbenvironment 提供了到用戶端資料庫的通路。它由 window 對象實作。
◆idbindex 提供了到索引中繼資料的通路。
◆idbkeyrange 定義鍵的範圍。
◆idbobjectstore 表示一個對象存儲空間。
◆idbopendbrequest 表示一個打開資料庫的請求。
◆idbrequest 提供了到資料庫異步請求結果和資料庫的通路。這也是在你調用一個異步方法時所得到的。
◆idbtransaction 表示一個事務。你在資料庫上建立一個事務,指定它的範圍(例如你希望通路哪一個對象存儲空間),并确定你希望的通路類型(隻讀或寫入)。
◆idbversionchangeevent 表明資料庫的版本号已經改變。
同步api
<a href="http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js">http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js</a>
<a href="http://caniuse.com/#feat=indexeddb">http://caniuse.com/#feat=indexeddb</a>
四、cookie
cookie(或者cookies),指一般網站為了辨識使用者身份、進行session跟蹤而儲存在使用者本地終端上的資料(通常經過加密)。cookie一般通過http請求中在頭部一起發送到伺服器端。一條cookie記錄主要由鍵、值、域、過期時間、大小組成,一般使用者儲存使用者的認證資訊。cookie最大長度和域名個數由不同浏覽器決定,具體如下:
浏覽器
支援域名個數
最大長度
ie7以上
50個
4095b
firefox
4097b
opera
30個
4096b
safari/webkit
無限制
不同域名之間的cookie資訊是獨立的,如果需要設定共享可以在伺服器端設定cookie的path和domain來實作共享。浏覽器端也可以通過document.cookie來擷取cookie,并通過js浏覽器端也可以友善地讀取/設定cookie的值。
<a href="https://github.com/component/cookie/blob/master/index.js">https://github.com/component/cookie/blob/master/index.js</a>
五、localstorage
localstorage是html5的一種新的本地緩存方案,目前用的比較多,一般用來存儲ajax傳回的資料,加快下次頁面打開時的渲染速度。
ie9以上
5m
firefox 8以上
5.24m
2m
2.6m
//localstorage核心api:
localstorage.setitem(key, value) //設定記錄
localstorage.getitem(key) //擷取記錄
localstorage.removeitem(key) //删除該域名下單條記錄
localstorage.clear() //删除該域名下所有記錄
值得注意的是,localstorage大小有限制,不适合存放過多的資料,如果資料存放超過最大限制會報錯,并移除最先儲存的資料。
<a href="https://github.com/machao/localstorage">https://github.com/machao/localstorage</a>
六、sessionstorage
sessionstorage和localstorage類似,但是浏覽器關閉則會全部删除,api和localstorage相同,實際項目中使用較少。
七、application cache
application cahce是将大部分圖檔資源、js、css等靜态資源放在manifest檔案配置中。當頁面打開時通過manifest檔案來讀取本地檔案或是請求伺服器檔案。
離線通路對基于網絡的應用而言越來越重要。雖然所有浏覽器都有緩存機制,但它們并不可靠,也不一定總能起到預期的作用。html5 使用applicationcache 接口可以解決由離線帶來的部分難題。前提是你需要通路的web頁面至少被線上通路過一次。
使用緩存接口可為您的應用帶來以下三個優勢:
◆離線浏覽 – 使用者可在離線時浏覽您的完整網站。
◆速度 – 緩存資源為本地資源,是以加載速度較快。
◆伺服器負載更少 – 浏覽器隻會從發生了更改的伺服器下載下傳資源。
一個簡單的離線頁面主要包含以下幾個部分:
index.html
<htmlmanifest="clock.manifest">
<head>
<title>appcache test</title>
<linkrel="stylesheet"href="clock.css">
<script src="clock.js"></script>
</head>
<body>
<p><outputid="clock"></output></p>
<divid="log"></div>
</body>
</html>
clock.manifest
cache manifest
#version 1.0
cache:
clock.css
clock.js
clock.js和clock.css為獨立的另外檔案。
另外,需要注意的是更新緩存。在程式中,你可以通過window.applicationcache 對象來通路浏覽器的app cache。你可以檢視 status 屬性來擷取cache的目前狀态:
var appcache = window.applicationcache;
switch (appcache.status) {
case appcache.uncached: // uncached == 0
return 'uncached';
break;
case appcache.idle: // idle == 1
return 'idle';
case appcache.checking: // checking == 2
return 'checking';
case appcache.downloading: // downloading == 3
return 'downloading';
case appcache.updateready: // updateready == 4
return 'updateready';
case appcache.obsolete: // obsolete == 5
return 'obsolete';
default:
return 'uknown cache status';
};
為了通過程式設計更新cache,首先調用 applicationcache.update()。這将會試圖更新使用者的 cache(要求manifest檔案已經改變)。最後,當 applicationcache.status 處于 updateready 狀态時, 調用applicationcache.swapcache(),舊的cache就會被置換成新的。
appcache.update(); // attempt to update the user’s cache.
…
if (appcache.status == window.applicationcache.updateready) {
appcache.swapcache(); // the fetch was successful, swap in the new cache.
}
這裡是通過更新menifest檔案來控制其它檔案更新的。
八、cachestorage
cachestorage是在serviceworker的規範中定義的。cachestorage 可以儲存每個serverworker申明的cache對象,cachestorage有open、match、has、delete、keys五個核心方法,可以對cache對象的不同比對進行不同的響應。
cachestorage.has()
如果包含cache對象,則傳回一個promise對象。
cachestorage.open()
打開一個cache對象,則傳回一個promise對象。
cachestorage.delete()
删除cache對象,成功則傳回一個promise對象,否則傳回false。
cachestorage.keys()
含有keys中字元串的任意一個,則傳回一個promise對象。
比對key中含有該字元串的cache對象,傳回一個promise對象。
caches.has('v1').then(function(){
caches.open('v1').then(function(cache){
return cache.addall(myassets);
});
}).catch(function(){
somecachesetupfunction();
});;
var response;
var cachedresponse = caches.match(event.request).catch(function(){
return fetch(event.request);
}).then(function(r){
response = r;
cache.put(event.request, response);
});
return response.clone();
return caches.match('/sw-test/gallery/mylittlevader.jpg');
then.addeventlistener('activate', function(event){
var cachewhitelist = ['v2'];
event.waituntil(
caches.keys().then(function(keylist){
return promise.all(keylist.map(function(key){
if (cachewhitelist.indexof(key) === -1) {
return caches.delete(keylist[i]);
}
});
})
);
九、flash緩存
這種方式基本不用,這一方法主要基于flash有讀寫浏覽器端本地目錄的功能,同時也可以向js提供調用的api,則頁面可以通過js調用flash去讀寫特定的磁盤目錄,達到本地資料緩存的目的。
注釋ps
◆web storage / web sql database / indexed database 的資料都存儲在浏覽器對應的使用者配置檔案目錄(user profile directory)下,以 windows 7 為例,chrome 的資料存儲在”c:\users\your-account-name\appdata\local\google\chrome\user data\default\”下,而 firefox 的資料存儲在”c:\users\your-account-name\appdata\local\mozilla\firefox\profiles\”目錄下。
◆cookie檔案存儲于documents and settings\username\cookie\檔案夾下。通常的命名格式為:[email protected]。
◆較多的緩存機制目前主流浏覽器并不相容,不過可以使用polyfill的方法來處理。
浏覽器涉及的緩存方式主要包含這些,具體結合自己的業務場景進行選擇使用。
作者:ouven
來源:51cto