ブラウザ側でデータを保存するため各ブラウザにおけるローカルストレージの挙動の調査

  • 161
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

このドキュメントではローカルストレージの説明と、各ブラウザでの動作を検証する。
ローカルストレージとは、データをブラウザ側に蓄積する仕組みである。

保存時に、サイトごとにKeyと文字の組み合わせでデータを格納する。

サイトごとの領域は、それぞれ独立しており、別のサイトで記録したデータを操作することはできない。
また、それぞれのサイト毎に保存できる上限は制限されている。その具体的サイズはブラウザ毎にことなる。

詳細な仕様は下記を参照のこと。
http://www.html5.jp/trans/w3c_webstorage.html

実装例

下記にローカルストレージの実装例を紹介する。

localStorage APIの使用例

localStorageの操作を行うAPIの使用例を紹介する。
このAPIは、処理が完了するまで制御の戻らない同期処理になっている。

指定のキーにデータを格納する

localStorage.setItem("KeyName","Data");

格納するデータは、文字列に過ぎない。
もし、オブジェクトを格納したい場合は、JSONを使用して変換をおこなうか、後述のstore.jsライブラリを使用すること。

サイト毎の容量を超えた場合は例外が発生する。
この時発生する例外はブラウザによって異なる。

以下にその一例を示す。

ブラウザ名 例外の名前
Fire fox 31.0 NS_ERROR_DOM_QUOTA_REACHED
Sarari 5.1.7 QUOTA_EXCEEDED_ERR
Chrome QuotaExceededError
IE11 QuotaExceededError

指定のキーの取得

console.log(localStorage.getItem("KeyName"))

存在しないキーを指定した場合はnullが返ってくる。

指定のキーの削除

localStorage.removeItem("keyName")

存在しないキーを指定してもエラーとならない。

すべてのキーの削除

localStorage.clear()

サイトに登録されているキーをすべて削除する。

登録されているキーの列挙

    var keys = [];
    for (var i = 0; i < localStorage.length; ++i) {
      keys.push(localStorage.key(i));
    }
    window.alert(keys.join("\n")); 

keyメソッドを使用すれば、キーの名称を取得できる。

store.js ローカルストレージ用のライブラリ

store.js
https://github.com/marcuswestin/store.js

store.jsはローカルストレージの操作を行うMITライセンスのライブラリである。
ローカルストレージが使用できる場合は、それを利用し、IE6,IE7などではuserData を用いて同等の処理を行う。
このライブラリにオブジェクトを渡すとJSONに変換して格納する。

storageイベント

setItem(), removeItem(), clear() メソッドが実行された時に、storageイベントが同じサイトを見ている、別のウィンドウで発行される。

以下にそのイベントを取得する例を示す。

  window.addEventListener("storage", function (event) {
    var data = 'key:' + event.key +
               ' oldValue:' + event.oldValue +
               ' newValue:' + event.newValue +
               ' url:' + event.url +
               ' storageArea:' + event.storageArea;
    console.log(event);
    $('#eventLog').append($('<option>').html(data));
  });

ブラウザを2つ開いて、片方でSetItemなどを行うと、もう片方でイベントが発行される。

ブラウザ間の挙動の差

ここでは検証用のコードを使用して各ブラウザのローカルストレージの動作にどのような差があるか検証する。
Windows7で下記のブラウザを対象とする。

・Fire fox 31.0
・Sarari 5.1.7
・Chrome 36.0.1985.125
・Internet Explore 11

検証用コード

下記のサイトにアクセスする。
http://needtec.sakura.ne.jp/release/storageTest.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Storage Sample</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.min.js"></script>

<script type="text/javascript">
$(function () {
  $('button').button();

  reloadStorage();

  // 指定のキーの値を更新
  $("#update").click(function(){
    localStorage.setItem($("#storeKey").val(),$("#storeMsg").val());
  });

  // 指定のキーの値を読み込む
  $("#reload").click(function(){
    reloadStorage();
  });

  // 指定のキーの値を削除
  $("#delete").click(function(){
    localStorage.removeItem($("#storeKey").val())
  });

  // 全て削除
  $("#clear").click(function(){
    localStorage.clear()
  });

  // キーの一覧
  $("#keyList").click(function(){
    var keys = [];
    for (var i = 0; i < localStorage.length; ++i) {
      keys.push(localStorage.key(i));
    }
    window.alert(keys.join("\n")); 
  });

  // 指定のサイズのデータを作成する
  $("#updateBigData").click(function() {
    try {
     var data = Array(parseInt($("#bigSize").val())).join("x");
     localStorage.setItem($("#storeKey").val(),data);
    } catch(e) {
      window.alert(e.name);
      window.alert(e);
    }
  });

  // オブジェクトで書き込む
  $("#testObject").click(function() {
    var obj;
    obj = {test:"123", value:123};
    localStorage.setItem("testObject",obj);
    window.alert(localStorage.getItem("testObject")); 
  });


  function reloadStorage() {
    $("#storeMsg").val(localStorage.getItem($("#storeKey").val()));
  }


  window.addEventListener("storage", function (event) {
    var data = 'key:' + event.key +
               ' oldValue:' + event.oldValue +
               ' newValue:' + event.newValue +
               ' url:' + event.url +
               ' storageArea:' + event.storageArea;
    console.log(event);
    $('#eventLog').append($('<option>').html(data));
  });
  window.addEventListener("storagecommit", function (event) {
    console.log("storagecommit");
    console.log(event);
  });


}); 
</script>
</head>
<body>
<p>
  KEY:
  <input id="storeKey" type="text" value="testData"></input>
</p>
<p>
  DATA:<BR>
  <textarea id="storeMsg" col="40" row="10"></textarea>
</p>
<p>
  EVENT:<BR>
  <select id="eventLog" multiple="multiple"></select>
</p>
<button id="update">update</button>
<button id="reload">reload</button>
<button id="testObject">testObject</button>
<button id="delete">delete</button>
<button id="clear">clear</button>
<button id="keyList">keyList</button>
<p>
  Big Data:<BR>
  <input id="bigSize" type="text" value="5242880"></input>
  <button id="updateBigData">update</button>
</p>
</body>
</html>

Fire fox 31.0

保存先:
C:\Users\ユーザ名\AppData\Roaming\Mozilla\Firefox\Profiles\wt12v6cu.default\webappsstore.sqlite
SQLiteの形式

イベントの挙動:
・自分のWindowで行った操作のイベントは、自分のWindowでは発行されない。
・setItemで前回値と同じ場合はイベントが発行されない。
・removeItemで存在しないキーを指定した場合、イベントは発行されない。
・clear済みで、再度、クリアしてもイベントは発行されない。

保存の限界:
キー名を「k」とし、5242640文字をデータとして保存した場合にNS_ERROR_DOM_QUOTA_REACHED例外が発生する。

ユーザによるローカルストレージの削除方法:
オプション⇒プライバシータブ⇒最近の履歴の消去よりCookieを削除する。

Sarari 5.1.7

保存先:
C:\Users\ユーザ名\AppData\Local\Apple Computer\Safari\LocalStorage
SQLiteの形式

イベントの挙動:
・自分のWindowで行った操作のイベントは、自分のWindowでは発行されない。
・setItemで前回値と同じ場合はイベントが発行されない。
・removeItemで存在しないキーを指定した場合、イベントは発行されない。
・clear済みで、再度、クリアしてもイベントは発行されない。

保存の限界:
キー名を「k」とし、2621440文字をデータとして保存した場合にQUOTA_EXCEEDED_ERR例外が発生する。

ユーザによるローカルストレージの削除方法:
設定⇒「プライバシー」タブよりCookieを削除する。

Chrome 36.0.1985.125

保存先:
C:\Users\ユーザ名\AppData\Local\Google\Chrome\User Data\Default\Local Storage\http_127.0.0.1_0.localstorage
SQLiteの形式

イベントの挙動:
・自分のWindowで行った操作のイベントは、自分のWindowでは発行されない。
・setItemで前回値と同じ場合はイベントが発行されない。
・removeItemで存在しないキーを指定した場合、イベントは発行されない。
・clear済みで、再度、クリアしてもイベントは発行されない。

保存の限界:
キー名を「k」とし、5242881文字をデータとして保存した場合にQuotaExceededError例外が発生する。

ユーザによるローカルストレージの削除方法:
設定⇒詳細設定の表示⇒履歴データの削除より、「Cookie と他のサイトやプラグインのデータ」を削除する。

Internet Explore 11

保存先:
C:\Users\ユーザ名\AppData\LocalLow\Microsoft\Internet Explorer\DOMStore\0FOJP942
XML形式

イベントの挙動:
・自分のWindowで行った操作のイベントでも、自分のWindowで発行される。
・setItemで前回値と同じ場合でもイベントが発行される。
・removeItemで存在しないキーを指定した場合でも、イベントは発行されない。
・clear済みで、再度、クリアした時に、イベントは発行される
・XMLにデータが書き込まれた時に、操作を行ったウィンドウだけにstoragecommitイベントが発行される。このイベントの取得例は下記の通り

  window.addEventListener("storagecommit", function (event) {
    console.log("storagecommit");
    console.log(event);
  });

・大量のデータをsetItemした場合の挙動が不安定
例:
 3000文字をsetItemする。⇒イベントが発生する。
 もう一度、3000文字をsetItemする。⇒イベントが発生しない
 一旦、キーを削除する。⇒イベントが発生する
 3000文字をsetItemする。⇒イベントが発生する。

保存の限界:
キー名を「k」とし、4999988文字をデータとして保存した場合にQuotaExceededError例外が発生する。

ユーザによるローカルストレージの削除方法:
オプション⇒「全般」タブ⇒閲覧の履歴の削除にて、「クッキーとWebサイトデータ」を選択して削除後、IEを再起動する。
http://msdn.microsoft.com/ja-jp/library/ie/bg142799%28v=vs.85%29.aspx

iOS

ipadなどではプライベートモードという、履歴を残さないモードがあります。

このモードではローカルストレージの取得では例外は発生しませんが、書き込みで例外が発生します。

try cacheで書き込めない場合にスクリプトが止まらないようにする必要があります。

まとめ

ローカルストレージを使用することで容易にクライアントサイドに情報を保持できる。
store.jsを用いれば、それはさらに容易になる

大きなデータの扱うのには適さない。この理由は二つある。
1つは同期処理のため、大きなデータを扱うと、そこで処理が止まる。
もう一つはサイト毎にストレージの上限が決められており、それは精々数MBであるからだ。

ストレージの上限は「わからない」ものとして処理した方が良い。

ユーザーがブラウザーの機能で、ローカルストレージをバックアップする手段はないので、消えたら困るデータは格納すべきでない。もし、格納する場合は、エクスポートの機能は必要だろう。

ストレージのイベントの使用は避けた方が良い。IE11の動きが極めて怪しい。

以上。