HTML5 の IndexedDB API を使用する

ローカル・データ永続化が Web アプリのアクセス性とモバイル・アプリの応答性を向上させます

HTML5 の一部となっている IndexedDB (Indexed Database) API は、ローカルにデータを保管する必要がある、リッチでデータ集約型のオフライン HTML5 Web アプリケーションを作成するのに役立ちます。また、データをローカルにキャッシュすることによって、モバイル Web アプリケーションなどの従来のオンライン Web アプリケーションの速度と応答性を向上させる上でも役に立ちます。この記事では、IndexedDB データベースを管理する方法を具体的な例で説明します。

Brian J Stewart, Principal Consultant, Aqua Data Technologies, Inc.

Photo of Brian StewartBrian J. Stewart は、Aqua Data Technologies で主任コンサルタントを務めています。彼が設立したこの会社は、コンテンツ・マネージメント、XML 技術、そしてエンタープライズ・クライアント/サーバーおよび Web システムを専門としています。彼は Java EE および Microsoft .NET プラットフォームをベースとしてエンタープライズ・ソリューションを設計、開発しています。



2013年 10月 24日

HTML5 の主要な特徴の 1 つは、オンラインであるかオフラインであるかに関わらず Web アプリケーションを利用可能にするローカル・データ永続化です。さらに、ローカル・データ永続化により、モバイル・アプリケーションの応答性が向上し、使用帯域幅が減り、低帯域幅のシナリオでの動作が効率化されます。HTML5 が提供するローカル・データ永続化には、いくつかの選択肢があります。選択肢の 1 つは、localstorage です。この場合、単純なキーと値のペアを使用してデータを格納することができます。IndexedDB はさらに強力な選択肢であり、膨大な数のオブジェクトをローカルに保管し、堅牢なデータ・アクセス・メカニズムによってデータを取得することができます。

IndexedDB API は、HTML5 仕様で非推奨となった Web Storage API に代わる API です (ただし、Apple の Safari や Opera など、いくつかの主要なブラウザーではまだ Web Storage をサポートしています)。IndexedDB には、インデックス機能、トランザクション機能、堅牢なクエリー機能をはじめとし、Web Storage よりも優れている点がいくつかあります。この記事では、一連の例をとおして IndexedDB データベースを管理する方法を説明します (これらの例の完全なソース・コードを入手するには、「ダウンロード」セクションを参照してください)。

主要な概念

Web サイトでは 1 つ以上の IndexedDB データベースを使用することができます。各データベースには、一意に決まる名前が付けられている必要があります。

データベースには 1 つ以上のオブジェクト・ストアを含めることができます。同じく名前で一意に識別されるオブジェクト・ストアは、レコードのコレクションです。各レコードには、キーと値があります。値はオブジェクトであり、そのオブジェクトには 1 つ以上のプロパティーまたは属性を設定することができます。キーは、キー・ジェネレーターに基づいてキー・パスから生成することも、明示的に設定することもできます。キー・ジェネレーターは、連続した一意の正の整数を自動的に生成します。キー・パスは、キー値へのパスを定義します。これは、単一の JavaScript ID であることも、ピリオドで区切られた複数の ID であることもあります。

IndexedDB API の仕様には、非同期 API と同期 API の両方が含まれます。同期 API は、Web ワーカー内で使用するためのものです。非同期 API は、リクエストとコールバックを使用します。

以降の例では、result という ID が設定された div タブに出力が追加されます。result 要素は、それぞれのデータ操作中に innerHTML プロパティーをクリアしてから設定することによって更新されます。サンプル JavaScript 関数は、いずれも HTML ボタンの onclick イベントによって呼び出されます。

エラーまたは例外の処理とデバッグ

すべての非同期リクエストには、データベース操作が成功すると呼び出される onsuccess コールバックと、操作が失敗すると呼び出される onerror コールバックがあります。リスト 1 は、onerror コールバックの例です。

リスト 1. 非同期エラー・ハンドラー
request.onerror = function(e) {
   // handle error
   ...
   console.log("Database error: " + e.target.errorCode);
};

IndexedDB API を扱っているときには、JavaScript の try/catch ブロックを使用することが得策です。この機能は、データベースが開いていないときにデータの読み取りやデータの操作を試行した場合や、別の読み取り/書き込みトランザクションがすでにオープンされているときにデータを書き込もうとした場合など、データベース操作の前に発生する可能性のあるエラーと例外を処理するのに役立ちます。

多くの場合にエラー・メッセージは一般的で参考にならないため、IndexedDB をデバッグしてトラブルシューティングするのが難しい可能性があります。アプリケーションを開発するときには、console.log や、JavaScript のデバッグ・ツール (例えば、Mozilla Firefox の Firebug や、Chrome に組み込まれているデベロッパー ツールなど) を利用してください。これらのツールは、JavaScript を駆使するアプリケーションであれば、どのアプリケーションにも有益ですが、IndexedDB API を使用する HTML5 アプリケーションにとっては特に掛け替えのないツールとなります。


データベースの操作方法

データベースに、同時に複数のバージョンが存在することはあり得ません。データベースが初めて作成されたときの初期バージョンはゼロです。データベースを作成した後は、versionchange トランザクションとして知られる特殊なタイプのトランザクションを使用しなければ、データベース (およびそのオブジェクト・ストア) に変更を加えることはできません。作成後のデータベースに変更を加えるには、現在のバージョン番号より大きいバージョン番号を指定してデータベースを開く必要があります。このアクションによって upgradeneeded イベントが起動されます。upgradeneeded イベント・ハンドラー内には、データベースまたはオブジェクトに変更を加えるためのコードが存在していなければなりません。

リスト 2 に記載するコード・フラグメントに、データベースを作成する方法を示します。open メソッドを呼び出してデータベース名を渡すと、その指定された名前を持つデータベースが存在しなければ、データベースが作成されます。

リスト 2. 新規データベースを作成する
function createDatabase() {
   var openRequest = localDatabase.indexedDB.open(dbName);

   openRequest.onerror = function(e) {
      console.log("Database error: " + e.target.errorCode);
   };
   openRequest.onsuccess = function(event) {
      console.log("Database created");
      localDatabase.db = openRequest.result;
   };
   openRequest.onupgradeneeded = function (evt) {
         ...
   };
}

既存のデータベースを削除する場合は、deleteDatabase メソッドを呼び出して、削除するデータベースの名前を渡します (リスト 3 を参照)。

リスト 3. 既存のデータベースを削除する
function deleteDatabase() {
   var deleteDbRequest = localDatabase.indexedDB.deleteDatabase(dbName);
   deleteDbRequest.onsuccess = function (event) {
      // database deleted successfully
   };
   deleteDbRequest.onerror = function (e) {
      console.log("Database error: " + e.target.errorCode);
   };
}

リスト 4 のコード・フラグメントは、既存のデータベースへの接続を開く方法を示しています。

リスト 4. 最新バージョンのデータベースを開く
function openDatabase() {
   var openRequest = localDatabase.indexedDB.open("dbName");
   openRequest.onerror = function(e) {
      console.log("Database error: " + e.target.errorCode);
   };
   openRequest.onsuccess = function(event) {

      localDatabase.db = openRequest.result;
   };
}

データベースを作成、削除、開くための操作は、これだけです。次は、オブジェクト・ストアの操作についての説明に移ります。


オブジェクト・ストアの操作方法

オブジェクト・ストアとは、データ・レコードのコレクションのことです。既存のデータベース内に新しいオブジェクト・ストアを作成するには、その既存のデータベースをバージョン管理する必要があります。それには、バージョン管理を目的にデータベースを開きます。open メソッドは、データベース名の他に、2 番目の引数としてバージョン番号も取ります。データベースの新しいバージョンを作成する場合 (つまり、オブジェクト・ストアを作成するか、オブジェクト・ストアに変更を加える場合) には、既存のデータベースのバージョン番号より大きいバージョン番号を指定してデータベースを開きます。これにより、onupgradeneeded イベント・ハンドラーが起動されます。

オブジェクト・ストアを作成するには、データベース・オブジェクトの createObjectStore メソッドを呼び出します (リスト 5 を参照)。

リスト 5. オブジェクト・ストアを作成する
function createObjectStore() {
   var openRequest = localDatabase.indexedDB.open(dbName, 2);
   openRequest.onerror = function(e) {
      console.log("Database error: " + e.target.errorCode);
   };
   openRequest.onsuccess = function(event) {
      localDatabase.db = openRequest.result;
   };
   openRequest.onupgradeneeded = function (evt) {
      var employeeStore = evt.currentTarget.result.createObjectStore
         ("employees", {keyPath: "id"});
   };
}

ここまででオブジェクト・ストアがどのように機能するかを説明したので、次は、データが含まれるオブジェクト・ストアをインデックスがどのように参照するかを見ていきましょう。


インデックスの使用方法

オブジェクト・ストアに含まれるレコードを取得するには、レコードのキーを使用するという方法の他に、インデックス付きフィールドを使用するという方法があります。オブジェクト・ストアには、1 つ以上のインデックスを割り当てることができます。インデックスは、データが含まれるオブジェクト・ストアを参照する特殊なオブジェクト・ストアです。参照先のオブジェクト・ストアが変更されると (つまり、レコードが追加、変更、または削除されると)、インデックスは自動的に更新されます。

インデックスを作成するには、リスト 5 に示した手法を使ってデータベースをバージョン管理する必要があります。インデックスは、一意である場合もそうでない場合もあります。一意のインデックスの場合、そのインデックスに含まれるすべての値が一意でなければなりません (例えば、e-メール・アドレス・フィールドの場合など)。一意でないインデックスは、市、都道府県、国など、値が繰り返される可能性がある場合に使用します。リスト 6 に記載するコード・フラグメントは、従業員オブジェクトの都道府県 (state) フィールドに一意でないインデックス、郵便番号 (zip_code) フィールドに一意でないインデックス、e-メール・アドレス (email) フィールドに一意のインデックスを作成する方法を示しています。

リスト 6. インデックスを作成する
function createIndex() {
   var openRequest = localDatabase.indexedDB.open(dbName, 2);
   openRequest.onerror = function(e) {
      console.log("Database error: " + e.target.errorCode);
   };
   openRequest.onsuccess = function(event) {
      db = openRequest.result;
   };
   openRequest.onupgradeneeded = function (evt) {
     var employeeStore = evt.currentTarget.result.objectStore("employees");
     employeeStore.createIndex("stateIndex", "state", { unique: false });
     employeeStore.createIndex("emailIndex", "email", { unique: true });
     employeeStore.createIndex("zipCodeIndex", "zip_code", { unique: false })
   };
}

続いて、オブジェクト・ストアに対し、トランザクションを使用して操作を実行します。


トランザクションの使用方法

オブジェクト・ストアに対する読み取り/書き込み操作は、すべてトランザクションを使用して行います。リレーショナル・データベースにおけるトランザクションの動作と同様で、IndexedDB トランザクションが提供するのは、完全にコミットされるか、まったくコミットされないかのいずれかの、アトミックなデータベース書き込み操作です。さらに、IndexedDB トランザクションには、データベース操作のアボート機能とコミット機能も用意されています。

表1 に、IndexedDB に用意されているトランザクション・モードとその説明を記載します。

表 1. IndexedDB トランザクション・モード
モード説明
readonlyオブジェクト・ストアに対する読み取りアクセスを提供します。オブジェクト・ストアに対してクエリーを実行するときに使用します。
readwriteオブジェクト・ストアに対する読み取り/書き込みアクセスを提供します。
versionchangeオブジェクト・ストアの定義を変更するため、または新規オブジェクト・ストアを作成するための読み取り/書き込みアクセスを提供します。

デフォルトのトランザクション・モードは readonly です。同時に複数の readonly トランザクションを行うことはできますが、readwrite トランザクションはいかなる時でも 1 つしかオープンすることができません。そのため、readwrite トランザクションは、データを更新する場合にのみ使用することを検討してください。シングルトン (他の同時トランザクションをオープンすることができないという意味) versionchange トランザクションは、データベースまたはオブジェクト・ストアを操作します。オブジェクト・ストアを作成、変更、削除する場合、またはオブジェクト・ストアにインデックスを追加する場合には、onupgradeneeded イベント・ハンドラー内で versionchange トランザクションを使用します。

employees オブジェクト・ストアのトランザクションを readwrite モードで作成するには、var transaction = db.transaction("employees", "readwrite"); というステートメントを使用します。

リスト 7 の JavaScript 関数は、トランザクションを使用して employees オブジェクト・ストア内の特定の従業員レコードを取得する方法を示しています。このトランザクションでは、キーを使用します。

リスト 7. キーを使用して特定のレコードを取得する
function fetchEmployee() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";
   if (localDatabase != null && localDatabase.db != null) {
     var store = localDatabase.db.transaction("employees").objectStore("employees");
     store.get("E3").onsuccess = function(event) {
      var employee = event.target.result;
      if (employee == null) {
         result.value = "employee not found";
      }
      else {
         var jsonStr = JSON.stringify(employee);
         result.innerHTML = jsonStr;
      }
     };
   }
}
catch(e){
   console.log(e);
}
}

リスト 8 の JavaScript 関数は、トランザクションを使用して employees オブジェクト・ストア内の特定の従業員レコードを取得するために、今度はオブジェクト・ストアのキーではなく emailIndex インデックスを使用します。

リスト 8. インデックスを使用して特定のレコードを取得する
function fetchEmployeeByEmail() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
      var range = IDBKeyRange.only("john.adams@somedomain.com");

      var store = localDatabase.db.transaction("employees")
.objectStore("employees");

      var index = store.index("emailIndex");

      index.get(range).onsuccess = function(evt) {
         var employee = evt.target.result;
         var jsonStr = JSON.stringify(employee);
         result.innerHTML = jsonStr;
      };
   }
}
catch(e){

リスト 9 は、readwrite トランザクションを使用して新規の従業員レコードを作成する例です。

リスト 9. 新規の従業員レコードを作成する
function addEmployee() {
   try {
      var result = document.getElementById("result");
      result.innerHTML = "";

      var transaction = localDatabase.db.transaction("employees", "readwrite");
      var store = transaction.objectStore("employees");

      if (localDatabase != null && localDatabase.db != null) {
         var request = store.add({
            "id": "E5",
            "first_name" : "Jane",
            "last_name" : "Doh",
            "email" : "jane.doh@somedomain.com",
            "street" : "123 Pennsylvania Avenue",
            "city" : "Washington D.C.",
            "state" : "DC",
            "zip_code" : "20500",
         });
         request.onsuccess = function(e) {
           result.innerHTML = "Employee record was added successfully.";
         };

         request.onerror = function(e) {
            console.log(e.value);
            result.innerHTML = "Employee record was not added.";
         };
      }
   }
   catch(e){
      console.log(e);
   }
}

リスト 10 は、readwrite トランザクションを使用して既存の従業員レコードを更新する例です。この例では、レコード ID が E3 に設定された従業員の e-メール・アドレスを変更します。

リスト 10. 既存の従業員レコードを更新する
function updateEmployee() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   var transaction = localDatabase.db.transaction("employees", "readwrite");
   var store = transaction.objectStore("employees");
   var jsonStr;
   var employee;

   if (localDatabase != null && localDatabase.db != null) {

      store.get("E3").onsuccess = function(event) {
         employee = event.target.result;
         // save old value
         jsonStr = "OLD: " + JSON.stringify(employee);
         result.innerHTML = jsonStr;

         // update record
         employee.email = "john.adams@anotherdomain.com";

         var request = store.put(employee);

         request.onsuccess = function(e) {
            console.log("Added Employee");
         };

         request.onerror = function(e) {
            console.log(e.value);
         };


         // fetch record again
         store.get("E3").onsuccess = function(event) {
            employee = event.target.result;
            jsonStr = "
NEW: " + JSON.stringify(employee); result.innerHTML = result.innerHTML + jsonStr; }; // fetch employee again }; // fetch employee first time } } catch(e){ console.log(e); } }

リスト 11 は、readwrite トランザクションを使用してオブジェクト・ストア内のすべてのレコードをクリア (削除) する例です。他の非同期トランザクションと同じく、clear トランザクションはオブジェクト・ストアがクリアされたかどうかに応じて、onsuccess コールバックまたは onerror コールバックを呼び出します。

リスト 11. オブジェクト・ストアをクリアするトランザクション
function clearAllEmployees() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
     var store = localDatabase.db.transaction("employees", "readwrite")
.objectStore("employees");

     store.clear().onsuccess = function(event) {
      result.innerHTML = "'Employees' object store cleared";
     };
   }
}
catch(e){
   console.log(e);
}
}

以上の例で、トランザクションの一般的な使用方法を実演しました。次は、Indexed DB でのカーソルの動作に目を向けます。


カーソルの使用方法

リレーショナル・データベースでのカーソルと同じように、IndexedDB のカーソルは、オブジェクト・ストアに含まれるレコードの繰り返し処理を可能にします。レコードの繰り返し処理には、オブジェクト・ストアのインデックスのうちの 1 つを使用することもできます。IndexedDB のカーソルは双方向のカーソルであるため、レコードを順方向にも逆方向にも繰り返し処理することができます。また、一意でないインデックスでは重複レコードをスキップすることも可能です。カーソルをオープンするためのメソッドは、openCursor です。このメソッドは、2 つのオプション引数 (範囲および方向) を取ります。

リスト 12 は、employees オブジェクト・ストアに対してカーソルをオープンし、すべての従業員レコードを繰り返し処理します。

リスト 12. すべての従業員レコードを繰り返し処理する
function fetchAllEmployees() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
      var store = localDatabase.db.transaction("employees")
.objectStore("employees");

      var request = store.openCursor();
      request.onsuccess = function(evt) {
         var cursor = evt.target.result;
         if (cursor) {
            var employee = cursor.value;
            var jsonStr = JSON.stringify(employee);
            result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; } } catch(e){ console.log(e); } }

以降に記載する例では、カーソルをインデックスとともに使用します。表 2 に、IndexedDB API がインデックスを使用してカーソルをオープンするときに使用できる範囲タイプまたはフィルターとその説明を記載します。

表 2. IndexedDB API がインデックスを使用してカーソルをオープンするときに使用できる範囲タイプまたはフィルター
範囲タイプまたはフィルター説明
IDBKeyRange.bound指定された範囲内のすべてのレコードを返します。この範囲は、上限と下限で指定されます。さらに、上限または下限のレコードを範囲に含めるかどうかを指定するための 2 つのオプション・パラメーター、lowerOpen および upperOpen があります。
IDBKeyRange.lowerBound指定された境界値を上回るすべてのレコードを返します。また、この範囲に下限値のレコードを含めるかどうかを指定するためのオプション・パラメーター lowerOpen があります。
IDBKeyRange.upperBound指定された境界値を下回るすべてのレコードを返します。また、この範囲に上限値のレコードを含めるかどうかを指定するためのオプション・パラメーター upperOpen があります。
IDBKeyRange.only指定された値と一致するレコードのみを返します。

リスト 13 に、特定の状態を対象に、すべての従業員レコードを繰り返し処理する基本的な例を記載します。ここに記載されているクエリーは最も一般的なものであり、特定の基準を満たすすべてのレコードを取得することができます。stateIndexIDBKeyRange.only 範囲を使用したこの例では、指定された値 (この場合は “New York”) と一致するすべてのレコードが返されます。

リスト 13. ニューヨークのすべての従業員レコードを繰り返し処理する
function fetchNewYorkEmployees() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
      var range = IDBKeyRange.only("New York");

      var store = localDatabase.db.transaction("employees")
.objectStore("employees");

      var index = store.index("stateIndex");

      index.openCursor(range).onsuccess = function(evt) {
         var cursor = evt.target.result;
         if (cursor) {
            var employee = cursor.value;
            var jsonStr = JSON.stringify(employee);
            result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; } } catch(e){ console.log(e); } }

リスト 14 は、IDBKeyRange.lowerBound 範囲の使用例です。この例では、郵便番号が 92000 より大きいすべての従業員が取得されます。

リスト 14. IDBKeyRange.lowerBound を使用する
function fetchEmployeeByZipCode1() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
     var store = localDatabase.db.transaction("employees").objectStore("employees");
     var index = store.index("zipIndex");

     var range = IDBKeyRange.lowerBound("92000");

     index.openCursor(range).onsuccess = function(evt) {
      var cursor = evt.target.result;
      if (cursor) {
         var employee = cursor.value;
         var jsonStr = JSON.stringify(employee);
         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; } } catch(e){ console.log(e); } }

リスト 15 は、IDBKeyRange.upperBound 範囲の使用例です。この例では、郵便番号が 93000 より小さいすべての従業員が取得されます。

リスト 15. IDBKeyRange.upperBound を使用する
function fetchEmployeeByZipCode2() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
     var store = localDatabase.db.transaction("employees").objectStore("employees");
     var index = store.index("zipIndex");

     var range = IDBKeyRange.upperBound("93000");

     index.openCursor(range).onsuccess = function(evt) {
      var cursor = evt.target.result;
      if (cursor) {
         var employee = cursor.value;
         var jsonStr = JSON.stringify(employee);
         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; } } catch(e){ console.log(e); } }

リスト 16 は、IDBKeyRange.bound 範囲の使用例です。この例では、郵便番号が 92000 から 92999 まで (下限と上限を含む) のすべての従業員が取得されます。

リスト 16. IDBKeyRange.bound を使用する
function fetchEmployeeByZipCode3() {
try {
   var result = document.getElementById("result");
   result.innerHTML = "";

   if (localDatabase != null && localDatabase.db != null) {
     var store = localDatabase.db.transaction("employees").objectStore("employees");
     var index = store.index("zipIndex");

     var range = IDBKeyRange.bound("92000", "92999", true, true);

     index.openCursor(range).onsuccess = function(evt) {
      var cursor = evt.target.result;
      if (cursor) {
         var employee = cursor.value;
         var jsonStr = JSON.stringify(employee);
         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; } } catch(e){ console.log(e); } }

これらの例では、IndexedDB でのカーソルの機能が、リレーショナル・データベースでのカーソルの機能といかに似ているかが明らかにされています。IndexedDB カーソルを使用すれば、オブジェクト・ストア内のレコードを繰り返し処理することや、オブジェクト・ストアのいずれかのインデックスを使用してレコードを繰り返し処理することができます。しかも IndexedDB のカーソルは双方向なので、柔軟性ももたらされます。


まとめ

IndexedDB API は堅牢な API です。ローカルにデータを保管する必要がある、リッチでデータ集約型のアプリケーション (具体的にはオフライン HTML5 Web アプリケーション) を作成するには、この API を利用することができます。また、IndexedDB API を使用してデータをローカルにキャッシュすれば、Web サーバーから毎回データを取得する必要がなくなるため、従来のオンライン Web アプリケーション (具体的にはモバイル Web アプリケーション) の速度と応答性が向上します。例えば、IndexedDB データベースでは、選択リスト用のデータをキャッシュすることができます。

この記事では、データベースの作成、データベースの削除、そしてデータベースへの接続の確立を含め、IndexedDB データベースを管理する方法を具体的な例で説明しました。さらに、IndexedDB API の高度な機能として、トランザクション、インデックス、カーソルについても説明しました。この記事で例示した概念を使用することで、IndexedDB API を利用するオフライン Web アプリケーションやモバイル Web アプリケーションを作成することができます。


ダウンロード

内容ファイル名サイズ
Source code examples for articleIndexedDBSourceCode.zip3KB

参考文献

学ぶために

製品や技術を入手するために

  • IBM 製品の評価版: DB2、Lotus、Rational、Tivoli、および WebSphere のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードしてみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=949089
ArticleTitle=HTML5 の IndexedDB API を使用する
publish-date=10242013