html5本次存儲幾種方式

1、cookies

  你們都懂的,沒必要多說javascript

2、sessionStorage/localStorage

HTML5 LocalStorage 本地存儲css

說到本地存儲,這玩意真是歷盡千辛萬苦才走到HTML5這一步,以前的歷史大概以下圖所示:html

 

最先的Cookies天然是你們都知道,問題主要就是過小,大概也就4KB的樣子,並且IE6只支持每一個域名20cookies,太少了。優點就是你們都支持,並且支持得還蠻好。很早之前那些禁用cookies的用戶也都慢慢的不存在了,就好像之前禁用javascript的用戶不存在了同樣。html5

 

userDataIE的東西,垃圾。如今用的最多的是Flash吧,空間是Cookie25倍,基本夠用。再以後Google推出了Gears,雖然沒有限制,但不爽的地方就是要裝額外的插件(沒具體研究過)。到了HTML5把這些都統一了,官方建議是每一個網站5MB,很是大了,就存些字符串,足夠了。比較詭異的是竟然全部支持的瀏覽器目前都採用的5MB,儘管有一些瀏覽器可讓用戶設置,但對於網頁製做者來講,目前的形勢就5MB來考慮是比較穩當的。java



支持的狀況如上圖,IE8.0的時候就支持了,很是出人意料。不過須要注意的是,IEFirefox測試的時候須要把文件上傳到服務器上(或者localhost),直接點開本地的HTML文件,是不行的。web

 

首先天然是檢測瀏覽器是否支持本地存儲。在HTML5中,本地存儲是一個window的屬性,包括localStoragesessionStorage,從名字應該能夠很清楚的辨認兩者的區別,前者是一直存在本地的,後者只是伴隨着session,窗口一旦關閉就沒了。兩者用法徹底相同,這裏以localStorage爲例。數據庫

if(window.localStorage){
 alert('This browser supports localStorage');
}else{
 alert('This browser does NOT support localStorage');
}編程

 

存儲數據的方法就是直接給window.localStorage添加一個屬性,例如:window.localStorage.a 或者 window.localStorage["a"]。它的讀取、寫、刪除操做方法很簡單,是以鍵值對的方式存在的,以下:json

localStorage.a = 3;//設置a"3"
localStorage["a"] = "sfsf";//設置a"sfsf",覆蓋上面的值
localStorage.setItem("b","isaac");//設置b"isaac"
var a1 = localStorage["a"];//獲取a的值
var a2 = localStorage.a;//獲取a的值
var b = localStorage.getItem("b");//獲取b的值
localStorage.removeItem("c");//清除c的值
後端

 

這裏最推薦使用的天然是getItem()setItem(),清除鍵值對使用removeItem()。若是但願一次性清除全部的鍵值對,可使用clear()。另外,HTML5還提供了一個key()方法,能夠在不知道有哪些鍵值的時候使用,以下:

var storage = window.localStorage;
function showStorage(){
 for(var i=0;i<storage.length;i++){
  //key(i)得到相應的鍵,再用getItem()方法得到對應的值
  document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
 }
}

 

寫一個最簡單的,利用本地存儲的計數器:

var storage = window.localStorage;
if (!storage.getItem("pageLoadCount")) storage.setItem("pageLoadCount",0);
storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必須格式轉換
document.getElementByIdx_x("count").innerHTML = storage.pageLoadCount;
showStorage();

不斷刷新就能看到數字在一點點上漲,以下圖所示:

 

須要注意的是,HTML5本地存儲只能存字符串,任何格式存儲的時候都會被自動轉爲字符串,因此讀取的時候,須要本身進行類型的轉換。這也就是上一段代碼中parseInt必需要使用的緣由。

 

另外,在iPhone/iPad上有時設置setItem()時會出現詭異的QUOTA_EXCEEDED_ERR錯誤,這時通常在setItem以前,先removeItem()ok了。

 

HTML5的本地存儲,還提供了一個storage事件,能夠對鍵值對的改變進行監聽,使用方法以下:

if(window.addEventListener){
 window.addEventListener("storage",handle_storage,false);
}else if(window.attachEvent){
 window.attachEvent("onstorage",handle_storage);
}
function handle_storage(e){
 if(!e){e=window.event;}
 //showStorage();
}

 

對於事件變量e,是一個StorageEvent對象,提供了一些實用的屬性,能夠很好的觀察鍵值對的變化,以下表:

 Property

 Type

 Description

 key

 String

 The named key that was added, removed, or moddified

 oldValue

 Any

 The previous value(now overwritten), or null if a new item was added

 newValue

 Any

 The new value, or null if an item was added

 url/uri

 String

 The page that called the method that triggered this change

 

這裏添加兩個鍵值對ab,並增長一個按鈕。給a設置固定的值,當點擊按鈕時,修改b的值:

<body>
<p>You have viewed this page <span id="count">0</span>  time(s).</p>
<p><input type="button" value="changeStorage" onClick="changeS()"/></p>
<script>
var storage = window.localStorage;
if (!storage.getItem("pageLoadCount")) storage.setItem("pageLoadCount",0);
storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必須格式轉換
document.getElementByIdx_x("count").innerHTML = storage.pageLoadCount;
showStorage();
if(window.addEventListener){
 window.addEventListener("storage",handle_storage,false);
}else if(window.attachEvent){
 window.attachEvent("onstorage",handle_storage);
}
function handle_storage(e){
 if(!e){e=window.event;}
 showObject(e);
}
function showObject(obj){
 //遞歸顯示object
 if(!obj){return;}
 for(var i in obj){
  if(typeof(obj[i])!="object" || obj[i]==null){
   document.write(i + " : " + obj[i] + "<br/>");
  }else{
   document.write(i + " : object" + "<br/>");
  }
 }
}
storage.setItem("a",5);
function changeS(){
 //修改一個鍵值,測試storage事件
 if(!storage.getItem("b")){storage.setItem("b",0);}
 storage.setItem('b',parseInt(storage.getItem('b'))+1);
}
function showStorage(){
 //循環顯示localStorage裏的鍵值對
 for(var i=0;i<storage.length;i++){
  //key(i)得到相應的鍵,再用getItem()方法得到對應的值
  document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
 }
}
</script>
</body>

 

測試發現,目前瀏覽器對這個支持不太好,僅iPadFirefox支持,並且Firefox支持得亂糟糟,e對象根本沒有那些屬性。iPad支持很是好,用的是e.uri(不是e.url),臺式機上的Safari不行,詭異。

 

目前瀏覽器都帶有很好的開發者調試功能,下面分別是ChromeFirefox的調試工具查看LocalStorage



另外,目前javascript使用很是多的json格式,若是但願存儲在本地,能夠直接調用JSON.stringify()將其轉爲字符串。讀取出來後調用JSON.parse()將字符串轉爲json格式,以下所示:

var details = {author:"isaac","description":"fresheggs","rating":100};
storage.setItem("details",JSON.stringify(details));
details = JSON.parse(storage.getItem("details"));

 

JSON對象在支持localStorage的瀏覽器上基本都支持,須要注意的是IE8,它支持JSON,但若是添加了以下的兼容模式代碼,切到IE7模式就不行了(此時依然支持localStorage,雖然顯示window.localStorage[object],而不是以前的[object Storage],但測試發現getItem()setItem()等均能使用)。

<meta content="IE=7" http-equiv="X-UA-Compatible"/>

3、web SQL / indexedDB

咱們常常在數據庫中處理大量結構化數據,html5引入Web SQL Database概念,它使用 SQL 來操縱客戶端數據庫的 API,這些 API 是異步的,規範中使用的方言是SQLlite,悲劇正是產生於此,Web SQL Database規範頁面有着這樣的聲明

image

This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path.

 大概意思就是

這個文檔曾經在W3C推薦規範上,但規範工做已經中止了。目前已經陷入了一個僵局:目前的全部實現都是基於同一個SQL後端(SQLite),可是咱們須要更多的獨立實現來完成標準化。

也就是說這是一個廢棄的標準了,雖然部分瀏覽器已經實現,但。。。。。。。

三個核心方法

可是咱們學一下也沒什麼壞處,並且能和如今W3C力推的IndexedDB作比較,看看爲何要廢棄這種方案。Web SQL Database 規範中定義的三個核心方法:

  1. openDatabase:這個方法使用現有數據庫或新建數據庫來建立數據庫對象
  2. transaction:這個方法容許咱們根據狀況控制事務提交或回滾
  3. executeSql:這個方法用於執行SQL 查詢

 

openDatabase

咱們可使用這樣簡單的一條語句,建立或打開一個本地的數據庫對象

var db = openDatabase('testDB', '1.0', 'Test DB', 2 * 1024 * 1024);

openDatabase接收五個參數:

  1. 數據庫名字
  2. 數據庫版本號
  3. 顯示名字
  4. 數據庫保存數據的大小(以字節爲單位 )
  5. 回調函數(非必須)

 

若是提供了回調函數,回調函數用以調用 changeVersion() 函數,無論給定什麼樣的版本號,回調函數將把數據庫的版本號設置爲空。若是沒有提供回調函數,則以給定的版本號建立數據庫。

transaction

transaction方法用以處理事務,當一條語句執行失敗的時候,整個事務回滾。方法有三個參數

  1. 包含事務內容的一個方法
  2. 執行成功回調函數(可選)
  3. 執行失敗回調函數(可選)

 

複製代碼
db.transaction(function (context) {
           context.executeSql('CREATE TABLE IF NOT EXISTS testTable (id unique, name)');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (0, "Byron")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (1, "Casper")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (2, "Frank")');
         });
複製代碼

這個例子中咱們建立了一個table,並在表中插入三條數據,四條執行語句任何一條出現錯誤,整個事務都會回滾

executeSql

executeSql方法用以執行SQL語句,返回結果,方法有四個參數

  1. 查詢字符串
  2. 用以替換查詢字符串中問號的參數
  3. 執行成功回調函數(可選)
  4. 執行失敗回調函數(可選)

在上面的例子中咱們使用了插入語句,看個查詢的例子

複製代碼
db.transaction(function (context) {
           context.executeSql('SELECT * FROM testTable', [], function (context, results) {
            var len = results.rows.length, i;
            console.log('Got '+len+' rows.');
               for (i = 0; i < len; i++){
              console.log('id: '+results.rows.item(i).id);
              console.log('name: '+results.rows.item(i).name);
            }
         });
複製代碼

完整示例

複製代碼
<!DOCTYPE HTML>
<html>
<head>
    <title>Web SQL Database</title>
</head>
<body>
    <script type="text/javascript">
        var db = openDatabase('testDB', '1.0', 'Test DB', 2 * 1024 * 1024);
        var msg;
        db.transaction(function (context) {
           context.executeSql('CREATE TABLE IF NOT EXISTS testTable (id unique, name)');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (0, "Byron")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (1, "Casper")');
           context.executeSql('INSERT INTO testTable (id, name) VALUES (2, "Frank")');
         });

        db.transaction(function (context) {
           context.executeSql('SELECT * FROM testTable', [], function (context, results) {
            var len = results.rows.length, i;
            console.log('Got '+len+' rows.');
               for (i = 0; i < len; i++){
              console.log('id: '+results.rows.item(i).id);
              console.log('name: '+results.rows.item(i).name);
            }
         });
        });
    </script>
</body>
</html>
複製代碼

最後

因爲Web SQL Database規範已經被廢棄,緣由說的很清楚,當前的SQL規範採用SQLite的SQL方言,而做爲一個標準,這是不可接受的,每一個瀏覽器都有本身的實現這還搞毛的標準。這樣瀏覽器兼容性就不重要了,估計慢慢會被遺忘。不過Chrome的控制檯真心好用啊,神馬cookie、Local Storage、Session Storage、Web SQL、IndexedDB、Application Cache等html5新增內容看的一清二楚,免去了不少調試代碼工做。

image

 

4、application Cahe

一、應用場景

離線訪問對基於網絡的應用而言愈來愈重要。雖然全部瀏覽器都有緩存機制,但它們並不可靠,也不必定總能起到預期的做用。HTML5 使用ApplicationCache 接口解決了由離線帶來的部分難題。前提是你須要訪問的web頁面至少被在線訪問過一次。

二、使用緩存接口可爲您的應用帶來如下三個優點:
離線瀏覽 – 用戶可在離線時瀏覽您的完整網站
速度 – 緩存資源爲本地資源,所以加載速度較快。
服務器負載更少 – 瀏覽器只會從發生了更改的服務器下載資源。
三、離線本地存儲和傳統的瀏覽器緩存有什麼不一樣呢?
離線存儲爲整個web提供服務,瀏覽器緩存只緩存單個頁面;
離線存儲能夠指定須要緩存的文件和哪些文件只能在線瀏覽,瀏覽器緩存沒法指定;
離線存儲能夠動態通知用戶進行更新。
四、如何實現

離線存儲是經過manifest文件來管理的,須要服務器端的支持,不一樣的服務器開啓支持的方式也是不一樣的。對於Tomcat須要修改 /conf/web.xml文件,添加以下MIMEType配置:

[html]  view plain copy
 
  1. <mime-mapping>  
  2.        <extension>manifest</extension>  
  3.        <mime-type>text/cache-manifest</mime-type>  
  4. </mime-mapping>  

注意,<extension>manifest</extension>中內容必須和manifest文件後綴名一致。

 

一個典型的manifest文件應該相似這樣:

 

[html]  view plain copy
 
  1. CACHE MANIFEST//必須以這個開頭  
  2. version 1.0 //最好定義版本,更新的時候只需修改版本號  
  3. CACHE:  
  4.     m.png  
  5.     test.js  
  6.     test.css  
  7. NETWORK:  
  8.     *  
  9. FALLBACK  
  10.     online.html offline.html  

其中CACHE指定須要緩存的文件;NETWORK指定只有經過聯網才能瀏覽的文件,*表明除了在CACHE中的文件;FALLBACK每行分別指定在線和離線時使用的文件
要讓manifest管理存儲。

有了manifest文件後,還須要在html標籤中定義manifest屬性,以下:

[html]  view plain copy
 
  1. <!DOCTYPE html>  
  2. <html lang="en" manifest='test.manifest'>  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title></title>  
  6. </head>  
  7. <body>  
  8.     
  9. </body>  
  10. </html>  

五、經過JS動態控制更新
應用在離線後將保持緩存狀態,除非發生如下某種狀況:
用戶清除了瀏覽器對您網站的數據存儲。
清單文件通過修改。請注意:更新清單中列出的某個文件並不意味着瀏覽器會從新緩存該資源。清單文件自己必須進行更改。

緩存狀態:
window.applicationCache 對象是對瀏覽器的應用緩存的編程訪問方式。其 status 屬性可用於查看緩存的當前狀態:

[html]  view plain copy
 
  1. var appCache = window.applicationCache;  
  2. switch (appCache.status) {  
  3.   case appCache.UNCACHED: // UNCACHED == 0  
  4.     return 'UNCACHED';  
  5.     break;  
  6.   case appCache.IDLE: // IDLE == 1  
  7.     return 'IDLE';  
  8.     break;  
  9.   case appCache.CHECKING: // CHECKING == 2  
  10.     return 'CHECKING';  
  11.     break;  
  12.   case appCache.DOWNLOADING: // DOWNLOADING == 3  
  13.     return 'DOWNLOADING';  
  14.     break;  
  15.   case appCache.UPDATEREADY:  // UPDATEREADY == 4  
  16.     return 'UPDATEREADY';  
  17.     break;  
  18.   case appCache.OBSOLETE: // OBSOLETE == 5  
  19.     return 'OBSOLETE';  
  20.     break;  
  21.   default:  
  22.     return 'UKNOWN CACHE STATUS';  
  23.     break;  
  24. };  

要以編程方式更新緩存,請先調用 applicationCache.update()。此操做將嘗試更新用戶的緩存(前提是已更改清單文件)。最後,當applicationCache.status 處於 UPDATEREADY 狀態時,調用 applicationCache.swapCache() 便可將原緩存換成新緩存。

 

[html]  view plain copy
 
  1. var appCache = window.applicationCache;  
  2. appCache.update(); // Attempt to update the user's cache.  
  3. ...  
  4. if (appCache.status == window.applicationCache.UPDATEREADY) {  
  5.   appCache.swapCache();  // The fetch was successful, swap in the new cache.  
  6. }  

 

請注意:以這種方式使用 update() 和 swapCache() 不會向用戶提供更新的資源。此流程只是讓瀏覽器檢查是否有新的清單、下載指定的更新內容以及從新填充應用緩存。所以,還須要對網頁進行兩次從新加載才能向用戶提供新的內容,其中第一次是得到新的應用緩存,第二次是刷新網頁內容。

好消息是,您能夠避免從新加載兩次的麻煩。要使用戶更新到最新版網站,可設置監聽器,以監聽網頁加載時的 updateready 事件:

[html]  view plain copy
 
  1. //Check if a new cache is available on page load.  
  2. window.addEventListener('load', function(e) {  
  3.   window.applicationCache.addEventListener('updateready', function(e) {  
  4.     if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {  
  5.       // Browser downloaded a new app cache.  
  6.       // Swap it in and reload the page to get the new hotness.  
  7.       window.applicationCache.swapCache();  
  8.       if (confirm('A new version of this site is available. Load it?')) {  
  9.         window.location.reload();  
  10.       }  
  11.     } else {  
  12.       // Manifest didn't changed. Nothing new to server.  
  13.     }  
  14.   }, false);  
  15. }, false);  

六、APPCACHE 事件(詳見W3C Spec:http://www.w3.org/TR/2012/WD-html5-20120329/offline.html#offline

 

Event name Interface Fired when... Next events
checking Event The user agent is checking for an update, or attempting to download the manifest for the first time. This is always the first event in the sequence. noupdatedownloading,obsoleteerror
noupdate Event The manifest hadn't changed. Last event in sequence.
downloading Event The user agent has found an update and is fetching it, or is downloading the resources listed by the manifest for the first time. progresserrorcached,updateready
progress ProgressEvent The user agent is downloading resources listed by the manifest. progresserrorcached,updateready
cached Event The resources listed in the manifest have been downloaded, and the application is now cached. Last event in sequence.
updateready Event The resources listed in the manifest have been newly redownloaded, and the script can use swapCache() to switch to the new cache. Last event in sequence.
obsolete Event The manifest was found to have become a 404 or 410 page, so the application cache is being deleted. Last event in sequence.
error Event The manifest was a 404 or 410 page, so the attempt to cache the application has been aborted. Last event in sequence.
The manifest hadn't changed, but the page referencing the manifest failed to download properly.
A fatal error occurred while fetching the resources listed in the manifest.
The manifest changed while the update was being run. The user agent will try fetching the files again momentarily.

經過對這些事件的監聽處理能更好的控制應用程序文件的緩存、更新。

 

7.一個簡單的離線緩存的應用
建一個web工程AppCache,包括四個文件:
appcache_offline.html

[html]  view plain copy
 
  1. <html manifest="clock.manifest">  
  2.   <head>  
  3.     <title>AppCache Test</title>  
  4.     <link rel="stylesheet" href="clock.css">  
  5.     <script src="clock.js"></script>  
  6.   </head>  
  7.   <body>  
  8.     <p><output id="clock"></output></p>  
  9.     <div id="log"></div>  
  10.   </body>  
  11. </html>  

clock.manifest

[html]  view plain copy
 
  1. CACHE MANIFEST  
  2. #VERSION 1.0  
  3. CACHE:  
  4. clock.css  
  5. clock.js  

clock.css

[html]  view plain copy
 
  1. output { font: 2em sans-serif; }  
[html]  view plain copy
 
  1. clock.js  
  2. setTimeout(function () {  
  3.     document.getElementById('clock').value = new Date();  
  4. }, 1000);  

聯網狀況下訪問:http://localhost:8080/AppCache/appcache_offline.html,頁面間斷顯示系統當前時間;斷開網絡後仍然能夠正常訪問。以下所示

相關文章
相關標籤/搜索