web前端實現本地存儲


  當我們在提及web前端本地存儲的時候,首先需要介紹一下本地化存儲的概念和歷史。本地化存儲從來不是一個新奇的概念,因為web應用程序一直在追求的就是媲美甚至超越桌面應用程序。但是桌面應用程序一直優於web應用程序一個很重要的原因是它的本地化存儲得到了很好的支持。對於本地應用程序,操作系統會提供一個抽象層,用於存儲和獲取特定於應用程序的數據,這些數據可以存儲於注冊表、INI文件,或者其他什么地方,這取決於操作系統的實現,如果本地應用程序需要不單是鍵值對形式的本地存儲,可以使用嵌入式數據庫或其他很多種解決方案。而對於web應用程序,它的本地存儲一步一步走到今天的HTML5本地存儲是非常不容易的。為了描述它的歷史,我們可以先看一張圖片:

Storage-support

  從圖片可以看出,無論是從存儲數據的大小還是兼容性來看,web前端本地存儲都走得不容易。在着重介紹HTML5本地存儲之前,我們先來看一看前面幾個存儲方式的概念。

  HTTP cookie:HTTP cookie的缺點很明顯,最多只能存儲4KB的數據,每個HTTP請求都會被傳送回服務器,明文傳輸(除非你使用SSL)。

  IE userData:userData是微軟在上世紀90年代的瀏覽器大戰時推出的本地存儲方案,借助DHTML的behaviour屬性來存儲本地數據, 允許每個頁面最多存儲64K數據,每個站點最多640K數據,userData的缺點顯而易見,它不是Web標准的一部分,除非你的程序只需要支持IE, 否則它基本沒什么用處。

  Flash cookie:Flash cookie的名字有些誤導,它實際上和HTTP cookie並不是一回事,或許它的名字應該叫做"Flash本地存儲”,Flash cookie默認允許每個站點存儲不超過100K的數據,如果超出了,Flash會自動向用戶請求更大的存儲空間,借助Flash的 ExternalInterface接口,你可以很輕松地通過Javascript操作Flash的本地存儲。Flash的問題很簡單,就是因為它是 Flash。

  Google Gears:Gears是Google在07年發布的一個開源瀏覽器插件,旨在改進各大瀏覽器的兼容性,Gears內置了一個基於SQLite的嵌入式 SQL數據庫,並提供了統一API對數據庫進行訪問,在取得用戶授權之后,每個站點可以在SQL數據庫中存儲不限大小的數據,Gears的問題就是 Google自己都已經不用它了。

  從上面的簡介我們可以看出,在以前,本地存儲面臨的主要問題是,對於存儲容量較大的方式,需要特定的插件支持;對於不需要插件支持的存儲方式,則處於安全問題或者大小限制而遭到扼殺。在這種雙重的矛盾面前,HTML5本地存儲橫空出世,對於前端開發人員是一種巨大的福音。

  所謂的HTML5本地存儲更精確的說法應該是DOM存儲。根據MDN的定義,DOM存儲的機制是通過存儲字符串類型的鍵/值對,來提供一種安全的存取方式.這個附加功能的目標是提供一個全面的,可以用來創建交互式應用程序的方法(包括那些高級功能,例如可以離線工作一段時間)。

  HTML5的DOM存儲分成兩種:SessionStorage和LocalStorage。在當代瀏覽器中的兼容性如下:

     Compatibility

  上圖中提及的globalStorage是非標准的,已經廢棄,在這里我們直接忽略它。而sessionStorage和localStorage在絕大部分現代瀏覽器中已經得到了很好的支持,但是既然是絕大部分,就必須照顧那些還不支持這兩個對象的瀏覽器。為了檢測瀏覽器是否支持這兩個對象,我們可以簡單的用下面的代碼來檢測:

1 function storageSupport() {  
2         try {  
3             return 'localStorage' in window && window['localStorage'] !== null;  
4         } catch (e) {  
5             return false;  
6         }  
7 }

  非常幸運的是,這兩種對象的使用方式都非常簡單,這里借用網上 的一張圖:

  Storage-usage   

  首先我們來看一看sessionStorage,sessionStorage 是個全局對象,它維護着在頁面會話(page session)期間有效的存儲空間。只要瀏覽器開着,頁面會話周期就會一直持續。當頁面重新載入(reload)或者被恢復(restores)時,頁面會話也是一直存在的。每在新標簽或者新窗口中打開一個新頁面,都會初始化一個新的會話。這句話看起來比較抽象,我們直接看一個demo:

1 var name = sessionStorage.setItem("myname","yuanzm");
2 alert(sessionStorage.getItem("myname"));

  當我們在瀏覽器中打開的時候,就會彈出窗口,顯示“yuanzm”,然后我們按F12鍵,查看瀏覽器的調試窗口:

  browser-sessionStorage

  我們能夠發現,在瀏覽器的本地存儲sessionStorage中已經有了key值為“myname”的項。這個時候,刷新頁面,仍然會彈出“yuanzm”,因為如果不調用sessionStorage.removeItem()或者手動清除這個項的話,這個項將一直存在。而上面提到的“只要瀏覽器開着,頁面會話周期就會一直持續。當頁面重新載入(reload)或者被恢復(restores)時,頁面會話也是一直存在的。每在新標簽或者新窗口中打開一個新頁面,都會初始化一個新的會話”的意思是說,如果我們不重新設置myname的值,在新打開一個瀏覽器標簽或者再次打開一個瀏覽器窗口的時候,這個值是不存在的,也就是null。為了驗證這一點,很簡單,我們把上面兩行代碼的第一行注釋掉,然后刷新頁面,接着在新的瀏覽器標簽中打開這個文件。這兩個動作分別會產生什么效果呢?答案很簡單,當再次刷新頁面的時候,仍然會彈出“yuanzm”,因為這個數據已經保存在本地了,而修改代碼之后在新的頁面打開,得到的結果是null,因為當前頁面會話中沒有“myname”這個值。

  接下來我們看一看localStorage,他是跨多個窗口,且持續范圍可超過當前會話;意味着當瀏覽器關閉再重新打開,數據依然是可用的;拿上面的例子來說,當修改代碼之后,在新的標簽打開頁面,仍然會彈出“yuanzm”,我們再次在瀏覽器中查看效果:

  brower-localStorage

  由於這兩個對象的使用很簡單,暫時就介紹到這里。下面還需要介紹一下的就是兼容性問題。原因很簡單,因為並不是所有的瀏覽器都支持這兩個對象。這里的兼容包括兩種,第一種是在沒有原生支持localStorage的瀏覽器中使用,第二種是兼容不同瀏覽器對於這兩種用法的差異。對於第一種,MDN給出了兼容代碼:

if (!window.localStorage) {
  Object.defineProperty(window, "localStorage", new (function () {
    var aKeys = [], oStorage = {};
    Object.defineProperty(oStorage, "getItem", {
      value: function (sKey) { return sKey ? this[sKey] : null; },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "key", {
      value: function (nKeyId) { return aKeys[nKeyId]; },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "setItem", {
      value: function (sKey, sValue) {
        if(!sKey) { return; }
        document.cookie = escape(sKey) + "=" + escape(sValue) + "; path=/";
      },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "length", {
      get: function () { return aKeys.length; },
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "removeItem", {
      value: function (sKey) {
        if(!sKey) { return; }
        var sExpDate = new Date();
        sExpDate.setDate(sExpDate.getDate() - 1);
        document.cookie = escape(sKey) + "=; expires=" + sExpDate.toGMTString() + "; path=/";
      },
      writable: false,
      configurable: false,
      enumerable: false
    });
    this.get = function () {
      var iThisIndx;
      for (var sKey in oStorage) {
        iThisIndx = aKeys.indexOf(sKey);
        if (iThisIndx === -1) { oStorage.setItem(sKey, oStorage[sKey]); }
        else { aKeys.splice(iThisIndx, 1); }
        delete oStorage[sKey];
      }
      for (aKeys; aKeys.length > 0; aKeys.splice(0, 1)) { oStorage.removeItem(aKeys[0]); }
      for (var iCouple, iKey, iCouplId = 0, aCouples = document.cookie.split(/\s*;\s*/); iCouplId < aCouples.length; iCouplId++) {
        iCouple = aCouples[iCouplId].split(/\s*=\s*/);
        if (iCouple.length > 1) {
          oStorage[iKey = unescape(iCouple[0])] = unescape(iCouple[1]);
          aKeys.push(iKey);
        }
      }
      return oStorage;
    };
    this.configurable = false;
    this.enumerable = true;
  })());
}
View Code

  至於第二種,在github上面有很多優秀的代碼,博主這里推薦其中一份:github localStorage

   最后,歡迎轉載原文,但是希望加上轉載鏈接:http://www.cnblogs.com/yuanzm/p/4023295.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM