1. 程式人生 > >HTML5 本地儲存初探

HTML5 本地儲存初探

隨著html5本地儲存的到來,web應用也會更加充滿活力。下面是個人對html5本地儲存的一些理解。

客戶端持久化資料的歷史:

HTTP cookie: 這個是客戶端使用的最為通用的方式,但問題也很明顯。典型情景是使用者本想執行一個事務,但可能會因為cookie而在不同視窗中執行多個事務。例如,一個使用者在兩個不同的視窗中登入同一個網站購買機票。網站使用cookie來記錄使用者購買的車票,當用戶在不同視窗之間點選時,cookie可能會導致使用者為同一個航班購買兩張機票。另外,cookie最多隻能儲存4KB資料,每個HTTP請求都要將其送回伺服器。

我們真正想要的是:

  • 更大的儲存空間

  • 客戶端持久化

  • 不受頁面重新整理的影響

  • 不需要提交到伺服器

HTML5本地儲存:

Web Storage是目前支援最廣泛的HTML5本地儲存規範,幾乎所有瀏覽器都支援。

瀏覽器通過實現localStorage等介面來支援webStorage。它讓 web 頁面能夠以鍵值對的形式,在客戶端web瀏覽器中將資料儲存在本地的方法。就像 cookie 一樣,這種資料在你離開 web 站點、關閉標籤頁、退出瀏覽器等等的時候依然儲存。不同於 cookie 的地方是,這個資料不會被髮送到遠端 web 伺服器(除非你自己手動傳送)。

其使用非常簡單:

var foo = "hello,localStorage";
localStorage.setItem("hello",foo);
var message = localStorage.getItem("hello");

通過註冊“storage”事件可以感知資料值的變化。

window.addEventListener('storage', function(e) {
    console.log(e.key + "'s value is changed from '" +
        e.oldValue + "' to '" + e.newValue + "' by " + e.url);
}, false);

//A page
localStorage['foo'] = 'bar';

//B page
localStorage['foo'] = 'newBar'

FileSystem API

當我們不滿足於鍵-值形式的本地儲存,而是想要自己管理本地儲存;或者覺得資料庫的支援不夠好,想擁有一個本地檔案系統一樣時,可能要考慮FileSystem API了。目前,只有chrome瀏覽器支援該特性。使用FileSystem API,web應用可以建立、讀寫、遍歷存在於沙箱(sandbox)中的使用者本地檔案系統的子集。

典型的好處如下:

1.  持久上傳

  •      當檔案或者目錄被選擇上傳時,資料被拷貝到本地沙箱中,並且一次上傳一部分。
  •      可以在瀏覽器崩潰或者網路故障後重新啟動上傳。

2.  視訊遊戲等擁有大量多媒體資源的應用

  •      下載壓縮包,本地解壓成目錄結構。
  •      下載與作業系統無關
  •       支援預取策略,從而使體驗更加流暢。
  •       伺服器端更加節省儲存。

3.  音訊、圖片離線編輯、快取加速

  •       目錄結構更加適合於該型別檔案的組織。
  •       被其他應用如iTunes、Picasa離線編輯

4.  離線視訊觀看

  •      為後續的觀看下載超過1GB的大檔案。
  •      方便快速seek播放
  •      部分播放,不用video標籤全部載入

5.  離線web 郵件客戶端

  •      下載附件,本地儲存。
  •      快取使用者選擇的附件以便快速上傳。
  •      上傳時可以作為多部分的post,而不是一次一個XHR裡面的檔案。

FileSystem API 程式碼示例,需要chrome以--unlimited-quota-for-files標誌執行,或者chrome web app 的manifest中開啟unlimitedStorage許可權

<!DOCTYPE html>
<html>
  <head>
    <style>
      .example {
        padding: 10px;
        border: 1px solid #CCC;
      }
      #example-list-fs ul {
        padding-left: 0;
      }
      #example-list-fs li {
        list-style: none;
      }
      #example-list-fs img {
        vertical-align: middle;
      }
      button {
        padding: 5px 8px;
        cursor: pointer;
        text-shadow: 1px 1px white;
        font-weight: 700;
        font-size: 10pt;
      }
      body {
        font: 14px Arial;
      }
    </style>
  </head>
  <body>
    <div id="example-list-fs" class="example">
      <button>Add some files</button> <button>List files</button> <button>Remove all files</button>
      <ul id="example-list-fs-ul"></ul>
    </div>
    <script>
      window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
      var fs = null;
      
      function errorHandler(e) {
        var msg = '';
        switch (e.code) {
          case FileError.QUOTA_EXCEEDED_ERR:
            msg = 'QUOTA_EXCEEDED_ERR';
            break;
          case FileError.NOT_FOUND_ERR:
            msg = 'NOT_FOUND_ERR';
            break;
          case FileError.SECURITY_ERR:
            msg = 'SECURITY_ERR';
            break;
          case FileError.INVALID_MODIFICATION_ERR:
            msg = 'INVALID_MODIFICATION_ERR';
            break;
          case FileError.INVALID_STATE_ERR:
            msg = 'INVALID_STATE_ERR';
            break;
          default:
            msg = 'Unknown Error';
            break;
        };
        document.querySelector('#example-list-fs-ul').innerHTML = 'Error: ' + msg;
      }
      
      function initFS() {
        window.requestFileSystem(window.TEMPORARY, 1024*1024, function(filesystem) {
          fs = filesystem;
        }, errorHandler);
      }
      
      var buttons = document.querySelectorAll('#example-list-fs button');
      var filelist = document.querySelector('#example-list-fs-ul');
      
      if (buttons.length >= 3) {
        buttons[0].addEventListener('click', function(e) {
          if (!fs) {
            return;
          }
          fs.root.getFile('log.txt', {create: true}, null, errorHandler);
          fs.root.getFile('song.mp3', {create: true}, null, errorHandler);
          fs.root.getDirectory('mypictures', {create: true}, null, errorHandler);
          filelist.innerHTML = 'Files created.';
        }, false);
      
        buttons[1].addEventListener('click', function(e) {
          if (!fs) {
            return;
          }
      
          var dirReader = fs.root.createReader();
          dirReader.readEntries(function(entries) {
            if (!entries.length) {
              filelist.innerHTML = 'Filesystem is empty.';
            } else {
              filelist.innerHTML = '';
            }
      
            var fragment = document.createDocumentFragment();
            for (var i = 0, entry; entry = entries[i]; ++i) {
              var img = entry.isDirectory ? '<img src="http://www.html5rocks.com/static/images/icon-folder.gif">' :
                                            '<img src="http://www.html5rocks.com/static/images/icon-file.gif">';
              var li = document.createElement('li');
              li.innerHTML = [img, '<span>', entry.name, '</span>'].join('');
              fragment.appendChild(li);
            }
            filelist.appendChild(fragment);
          }, errorHandler);
        }, false);
      
        buttons[2].addEventListener('click', function(e) {
          if (!fs) {
            return;
          }
      
          var dirReader = fs.root.createReader();
          dirReader.readEntries(function(entries) {
            for (var i = 0, entry; entry = entries[i]; ++i) {
              if (entry.isDirectory) {
                entry.removeRecursively(function() {}, errorHandler);
              } else {
                entry.remove(function() {}, errorHandler);
              }
            }
            filelist.innerHTML = 'Directory emptied.';
          }, errorHandler);
        }, false);
      }
      
      // Initiate filesystem on page load.
      if (window.requestFileSystem) {
        initFS();
      }
    </script>
  </body>
</html>​

綜上,HTML5的本地儲存特性,將會給未來的web應用帶來更豐富的特性,從而大幅提升使用者體驗。

參考資料: