Get to know MDN better
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
IndexedDB は、ユーザーのブラウザー内にデータを永続的に保存する手段です。ネットワークの状態にかかわらず高度な問い合わせ機能を持つウェブアプリケーションを作成できますので、アプリケーションがオンラインとオフラインの両方で動作するようになります。
このチュートリアルでは、IndexedDB の非同期 API の使い方を見ていきます。IndexedDB について詳しくない場合は、始めに IndexedDB の主な特徴と基本用語をお読みください。
IndexedDB API のリファレンスドキュメントとして、IndexedDB API の記事とそのサブ記事をご覧ください。この記事では、IndexedDB で使用されるオブジェクトの種類と、非同期 API のメソッドについて説明します (同期 API は仕様から削除されました)。
IndexedDB で推奨される基本パターンは、以下のようになります。
これらの主要な概念を踏まえることで、より具体的な手続きを理解できます。
プロセス全体は以下のようにして始めます。
わかりますか? データベースを開くことも他の操作と同様であり、「リクエスト」が必要です。
データベースを開くリクエストは、すぐにはデータベースを開いたりトランザクションを開始したりはしません。open() 関数を呼び出すと、結果 (成功) またはイベントとして扱うエラー値を伴う IDBOpenDBRequest オブジェクトを返します。IndexedDB のほとんどの他の非同期関数も同様であり、結果またはエラーを伴う IDBRequest オブジェクトを返します。open 関数の結果は IDBDatabase のインスタンスです。
open メソッドの第 2 引数は、データベースのバージョンです。データベースのバージョンは、データベースのスキーマ、すなわちデータベース内のオブジェクトストアとその構造を決定します。データベースが存在しない場合に open 操作でデータベースが作成されると、onupgradeneeded イベントが発生し、そのイベントハンドラーでデータベースのスキーマを作成することができます。データベースが存在する場合に従来より高いバージョン番号を指定すると、すぐに onupgradeneeded イベントが発生して、そのイベントハンドラーで更新されたスキーマを提供することができます。詳しくは、後ほどデータベースのバージョンの作成と更新で説明します。また、 IDBFactory.open のリファレンスページもご覧ください。
警告: バージョン番号は unsigned long long 型の数値であり、とても大きい整数にすることができます。また浮動小数点数値は使用できず、使用した場合は upgradeneeded イベントが発生せず、もっとも近い小さな数値に変換されてトランザクションが始まるでしょう。よって、例えばバージョン番号として 2.4 を使用しないでください。 const request = indexedDB.open("MyTestDatabase", 2.4); // 行ってはいけません。バージョンは 2 に丸められます
ほぼすべてのリクエスト生成に合わせて始めに行いたいことは、成功およびエラーのハンドラーを生成することでしょう。
リクエストが成功した場合、success イベントが発生し、onsuccess に代入された関数が呼び出されます。リクエストが失敗した場合、error イベントが発生し、onerror に代入された関数が呼び出されます。
IndexedDB API は必要なエラー処理を最小限にするよう設計されていますので、多くのエラーイベントを見ることはないでしょう (少なくとも、API に慣れていなければ)。しかしデータベースを開く場合は、エラーイベントが発生する一般的な状況があります。もっとも多いであろう問題は、データベースを作成する許可をユーザーがウェブアプリに与えなかったことです。IndexedDB の主要な設計目標のひとつが、オフラインで使用するために大量のデータを保存できるようにすることです。(各ブラウザーでどれだけの量のストレージを持てるかについては、ブラウザーのストレージ制限と削除基準ページ内のどれだけのデータが格納できるかをご覧ください)
広告ネットワークやコンピューターを汚染させる悪意のあるウェブサイトをブラウザーが許可したくないことは明らかですので、ブラウザーは ウェブアプリが初めてストレージ用に IndexedDB を開こうとしたときに、ユーザーへプロンプトを表示します。ユーザーはアクセスを許可または拒否できます。またブラウザーのプライバシーモードでの IndexedDB ストレージは、匿名のセッションを閉じるまでの間だけメモリー上に存在します。
ユーザーがデータベース作成の要求を許可して、成功コールバックを実行する成功イベントを受け取ったと想定します。次は何を行うのでしょうか? 以下のリクエストは indexedDB.open() の呼び出しを伴って生成されており、request.result は IDBDatabase のインスタンスですので、以降のためにこれを保存したいことは確実です。よって、コードは以下のようになるでしょう。
前述のとおり、エラーイベントはバブリングします。エラーイベントはエラーを発生させたリクエストをターゲットにして、さらにトランザクションや最終的にデータベースオブジェクトへバブリングします。すべてのリクエストにエラーハンドラーを追加することを避けたい場合は、代わりに以下のように、ひとつのエラーハンドラーをデータベースオブジェクトに追加することができます。
データベースを開く際によく発生するエラーのひとつが VER_ERR です。これはディスクに保存されているデータベースのバージョンが、開こうとしているバージョンより大きいことを表します。これは、必ずエラーハンドラーで処理しなければならないエラーの実例です。
新しいデータベースを作成したり既存のデータベースのバージョンを更新したりする (データベースを開く際に、従来より大きなバージョン番号を指定する) と onupgradeneeded イベントが発生して、request.result (すなわち、以下の例の db) に設定した onversionchange イベントハンドラーに IDBVersionChangeEvent オブジェクトが渡されます。upgradeneeded イベントのハンドラーでは、このバージョンのデータベースで必要なオブジェクトストアを作成します。
この場合、データベースは旧バージョンのデータベース由来のオブジェクトストアをすでに持っていますので、それらのオブジェクトストアを再作成する必要はありません。新しいオブジェクトストアを作成するか、不要になった旧バージョンのオブジェクトストアを削除することだけが必要です。既存のオブジェクトストアを変更しなければならない (例えば keyPath を変更する) 場合は、古いオブジェクトストアを削除してから、新たな設定で再作成しなければならりません。(これはオブジェクトストア内の情報を削除しますので注意してください! この情報を保存しなければならない場合は、データベースをアップグレードする前にデータを読み出して、別の場所に保存してください)
既存の名称を使用してオブジェクトストアを作成しようとする (あるいは、存在しない名称のオブジェクトストアを削除しようとする) と、エラーが発生します。
onupgradeneeded イベントから正常に抜けた場合は、データベースを開くリクエストの onsuccess ハンドラーが実行されます。
次に、データベースを構築します。IndexedDB はテーブルではなくオブジェクトストアを使用しており、ひとつのデータベースに複数のオブジェクトストアを含めることができます。値をオブジェクトストアへ保存するたびに、値がキーと関連付けられます。オブジェクトストアでキーパスを使用するかキージェネレーターを使用するかに応じて、キーを供給する方法がいくつか存在します。
以下の表で、キーを供給するさまざまな方法を示します。
| なし | なし | このオブジェクトストアは、数値や文字列といったプリミティブ値を含む、どのような種類の値でも保持できます。新たな値の追加を望むたびに、個別のキー引数を供給しなければなりません。 |
| あり | なし | このオブジェクトストアは、JavaScript オブジェクトのみ保持できます。オブジェクトはキーパスと同じ名称のプロパティを持たなければなりません。 |
| なし | あり | このオブジェクトストアは、どのような種類の値でも保持できます。キーは自動的に生成されます。また、特定のキーを使用したい場合は個別のキー引数を供給できます。 |
| あり | あり | このオブジェクトストアは、JavaScript オブジェクトのみ保持できます。通常はキーが生成されて、オブジェクトでキーパスと同じ名称を持つプロパティに、生成されたキーの値を保存します。ただしそのようなプロパティがすでに存在している場合は、生成された新たなキーではなく、そのプロパティの値をキーとして使用します。 |
オブジェクトストアがプリミティブではなくオブジェクトを保持していれば、オブジェクトストアでインデックスを作成することもできます。インデックスは、オブジェクトのキーではなく保存されたオブジェクトのプロパティの値を使用して、オブジェクトストア内に保存された値を検索することを可能にします。
さらにインデックスには、保存されたデータに単純な制限を強制する機能があります。インデックスを作成する際に unique フラグを設定すると、インデックスのキーパスで同じ値を持つオブジェクトが複数保存されないことを、インデックスが保証します。よって例えば人々の集団の情報を保持するオブジェクトストアがある場合に、同じメールアドレスを持つ人が 2 人存在しないことを保証したい場合は、これを強制するために unique フラグを設定したインデックスを使用するとよいでしょう。
これには混乱するかもしれませんので、シンプルな例で概念を説明するべきでしょう。始めに、例で使用する顧客データをいくつか定義します。
もちろん、誰かの社会保障番号を顧客テーブルの主キーとして使用するべきではないですし (社会保障番号を持っていない人もいます)、年齢の代わりに誕生日を保管することもできますが、これらの不適切な選択は利便性のために無視して先へ進みましょう。
次に、データを保存する IndexedDB を作成するところを見てみましょう。
先に示したように、onupgradeneeded はデータベースの構造を変えることができる唯一の場所です。ここではオブジェクトストアの作成および削除や、インデックスの構築および削除が可能です。
オブジェクトストアは createObjectStore() を 1 回呼び出して作成します。このメソッドの引数は、ストアの名前と引数オブジェクトです。引数オブジェクトは省略可能ですが、重要なオプションプロパティを定義したり、作成したいオブジェクトストアの型を改良することができますので、とても重要です。この例では "customers" という名前のオブジェクトストアを要求して、keyPath を定義しています。keyPath は、ストア内で個々のオブジェクトを一意にするプロパティです。この例では、社会保障番号が一意であることが保証されていますので "ssn" にしています。"ssn" は、objectStore に保存するすべてのオブジェクトに与えなければなりません。
また、保存されたオブジェクトの name プロパティを参照する、"name" という名前のインデックスも要求しています。createObjectStore() と同様に createIndex() も、作成したいインデックスの型を改良するための省略可能な引数 options オブジェクトを指定できます。name プロパティを持たないオブジェクトを追加することはできますが、そのオブジェクトは "name" インデックス内に現れません。
以上でオブジェクトストアに保存された顧客オブジェクトを、ssn を使用して直接、またはインデックスを使用して名前をもとにして、取り出すことができます。この仕組みについて詳しくは、インデックスの使用をご覧ください。
オブジェクトストアを作成するときに autoIncrement フラグを設定すると、そのオブジェクトストアでキージェネレーターを使用できます。デフォルトで、このフラグは設定されません。
キージェネレーターを使用すると、オブジェクトストアに値を追加するのに応じて自動的にキーが生成されます。オブジェクトストアでキージェネレーターを初めて作成した時点では、キージェネレーターの値が常に 1 になります。基本的に、新たに自動生成されるキーは、前のキーから 1 増加した値になります。データベースのトランザクションが中止されるなど、データベースの操作が取り消された場合を除き、キージェネレーターの現在の値が減少することはありません。従って、オブジェクトストアからレコードを削除したりすべてのレコードをクリアしたりしても、オブジェクトストアのキージェネレーターには影響がありません。
以下のように、キージェネレーターを持つ別のオブジェクトストアを作成できます。
キージェネレーターについて詳しくは、仕様書の Key generators をご覧ください。
新しいデータベースで何かを行えるようにする前に、トランザクションを開始しなければなりません。トランザクションはデータベースオブジェクトから生じており、トランザクションの対象にしたいオブジェクトストアを指定しなければなりません。トランザクションの内部では、データを保持しているオブジェクトストアへのアクセスや、リクエストの実行が可能です。次に、データベースに変更処理を行うのか、あるいはデータベースから読み出すだけかを決めなければなりません。トランザクションは readonly、readwrite、versionchange の 3 つのモードを使用できます。
データベースの「スキーマ」や構造を変更する (オブジェクトストアやインデックスを作成または削除する) には、トランザクションを versionchange モードにしなければなりません。このトランザクションは、version を指定して IDBFactory.open メソッドを呼び出すことによって開きます。
既存のオブジェクトストアからレコードを読み出すには、トランザクションで readonly モードまたは readwrite モードを使用できます。既存のオブジェクトストアに変更処理を行うには、トランザクションを readwrite モードにしなければなりません。このようなトランザクションは IDBDatabase.transaction で開きます。このメソッドの引数は 2 つあり、storeNames (アクセスしたいオブジェクトストアの配列で定義されるスコープ) とトランザクションの mode (readonly または readwrite) です。またこのメソッドは、IDBTransaction.objectStore メソッドを持つトランザクションオブジェクトを返します。objectStore メソッドは、オブジェクトストアにアクセスするために使用できます。デフォルトでは、モードを指定しなければ readonly モードでトランザクションを開きます。
メモ: Firefox 40 で、IndexedDB トランザクションはパフォーマンスを向上させるために、永続性の保証を緩和しました (Firefox bug 1112702 を参照)。以前は readwrite モードのトランザクションで、すべてのデータをディスク上に反映したことが保証された場合に限り complete 発生しました。Firefox 40 以降では OS がデータの書き込みを指示した時点で complete が発生しており、実際にはデータがディスク上に反映されていない可能性があります。これにより complete イベントをより早く発生させられますが、データをディスク上に反映する前に OS のクラッシュや電源断が発生するとトランザクション全体を失う危険性が若干あります。このような破壊的な事象はまれですので、ほとんどの利用者は心配する必要がないでしょう。何らかの理由 (例えば、後で再計算できない重要なデータを保存する) で永続性を保証しなければならない場合は、実験的 (非標準) な readwriteflush モード (IDBDatabase.transaction を参照) を使用してトランザクションを生成すると、complete イベントを発生させる前にディスクへの反映を強制させることができます。
トランザクションで適切なスコープおよびモードを使用すると、データアクセスを高速化できます。ヒントを 2 つ紹介します。
データベースを作成したら、書き込みを行いたいと考えるでしょう。これは以下のようにします。
transaction() 関数は引数が 2 つあり (ひとつは省略可能)、トランザクションオブジェクトを返します。第 1 引数は、トランザクションの対象にするオブジェクトストアのリストです。トランザクションですべてのオブジェクトを対象にしたい場合は空の配列を渡すことができますが、仕様書では空の配列に対して InvalidAccessError を生成すべきとされていますので、行わないようにしてください。第 2 引数に何も指定しなければ、読み取り専用のトランザクションになります。書き込みを行いたい場合は、"readwrite" フラグを渡さなければなりません。
以上で、存続期間を理解しなければならないトランザクションができました。トランザクションは、イベントループととても密接に結びついています。トランザクションを作成して、それを使用せずにイベントループに戻ると、トランザクションが非アクティブ状態になります。トランザクションをアクティブにし続ける唯一の方法が、トランザクションでリクエストを行うことです。リクエストが完了すると DOM イベントが発生して、リクエストが成功したと仮定すれば、コールバックの実行中にトランザクションを拡張するもうひとつの機会を得られます。トランザクションを拡張せずにイベントループへ戻ると、トランザクションは非アクティブ状態になります。保留中のリクエストがある限り、トランザクションはアクティブであり続けます。トランザクションの存続期間はごくシンプルですが、慣れるまでには少々時間がかかるでしょう。さらにいくつかの例も、理解する助けになるでしょう。TRANSACTION_INACTIVE_ERR エラーコードを見始めた場合は、何らかの誤りがあるでしょう。
トランザクションは error、abort、complete の 3 種類の DOM イベントを受け取る可能性があります。error イベントがバブリングする方法について話したとおり、トランザクションは、生成したあらゆるリクエストが由来のエラーイベントを受け取ります。より細かいポイントとして、エラー時のデフォルトの動作は、エラーが発生したトランザクションを中止させることです。エラーイベントで始めに stopPropagation() を呼び出して、他の処理を行うようにエラー制御を行わなければ、トランザクション全体がロールバックします。この設計によってエラー制御を考えるよう強いられますが、きめ細かいエラー制御がとても複雑になる場合は、データベースに対して包括的なエラー制御を追加することもできます。エラーイベントを制御しない場合やトランザクションで abort() を呼び出した場合は、トランザクションがロールバックされて、abort イベントが発生します。それ以外の場合は、すべての保留中のリクエストが完了した後に complete イベントが発生します。多くのデータベース操作を行っている場合は、個々のリクエストではなくトランザクションを追跡すると、確実に健全性を促進します。
トランザクションを確保したら、そこからオブジェクトストアを取得しなければならないでしょう。トランザクションは、作成時に指定したオブジェクトストアだけを提供します。そして、必要なデータをすべて追加できます。
add() を呼び出して生成されたリクエストの result は、追加された値のキーです。よってこのケースでは、オブジェクトストアでキーパスとして ssn プロパティを使用していますので、追加されたオブジェクトの ssn プロパティと等しくなります。add() 関数では、データベース内に同一のキーを持つオブジェクトが存在しないことを要求しますので注意してください。既存の項目を変更しようとする場合や、既存の項目があるかを配慮しない場合は、データベース内の項目の更新の節で説明している put() 関数を使用できます。
データの削除もよく似ています。
データベースは情報を持っていますので、いくつかの方法でデータを読み出すことができます。まずは、単純に get() を使用します。以下のように、値を読み出すためにキーを提供しなければなりません。
"単純に" 読み出すにも多くのコードがあります。データベースレベルでエラー処理を行うとすれば、コードを少々短縮できることを以下に示します。
どのように動作するかわかりますか? オブジェクトストアが 1 つしかありませんので、トランザクションで必要とするオブジェクトストアのリストを渡さずに、名称を文字列で渡しています。また、データベースから読み出すだけですので、"readwrite" トランザクションは不要です。モードを指定せずに transaction() を呼び出すと、"readonly" トランザクションになります。さらに細かいことですが、実はリクエストオブジェクトを変数に保存していません。DOM イベントはターゲットとしてリクエストを持ちますので、result プロパティを得るためにイベントを使用できます。
読み出したデータを更新して IndexedDB に書き戻す方法は、とてもシンプルです。先ほどのサンプルを多少更新しましょう。
ここでは objectStore を作成して、ssn の値 (444-44-4444) で特定される顧客レコードの取り出しを要求しています。リクエストの結果を変数 (data) に代入して、そのオブジェクトの age プロパティを更新します。そして、顧客レコードを objectStore に書き戻して前の値を上書きする、第 2 のリクエスト (requestUpdate) を作成します。
メモ: このケースではデータベースから読み出すだけでなく書き込みも行いたいので、readwrite トランザクションを指定しました。
get() を使用する際は、読み出したいキーがどれかを知っていることが必要です。オブジェクトストア内のすべての値を渡り歩きたい場合は、カーソルを使用できます。以下のようなものです。
openCursor() 関数は、引数がいくつかあります。第一に、すぐに取得するキーレンジオブジェクトを使用して、読み出すアイテムの範囲を制限できます。第二に、反復処理を行いたい方向を指定できます。上記の例では、すべてのオブジェクトを昇順方向に反復します。カーソルの成功イベントのコールバックは、やや特殊です。カーソルオブジェクト自体は、リクエストの result です (上記の例では略記法を使用しており、event.target.result になります)。そして実際のキーと値は、カーソルオブジェクトの key プロパティと value プロパティで見つかります。進み続けたい場合は、カーソルで continue() を呼び出さなければなりません。データの終端に達した (または、openCursor() リクエストに一致する項目が存在しない) 場合は成功のコールバックを受け取りますが、result プロパティが undefined になります。
カーソルをよく使用するパターンのひとつが、以下のようにオブジェクトストア内の全データを読み出して、配列に追加することです。
メモ: それ以外に、このような処理を行うために getAll() (および getAllKeys())。を使用することができます。以下のコードは、前出の例とまったく同じことを行います。
これはオブジェクトを横着な方法で作成するため、カーソルの value プロパティの検索に関してパフォーマンスコストが発生します。例えば getAll() を使用するとき、Gecko はすべてのオブジェクトを一度に作成しなければなりません。例えばそれぞれのキーを検索することにのみ関心がある場合は、getAll() よりもカーソルを使用する方がとても効率的です。オブジェクトストア内の全データの配列を得ようとしている場合は、getAll() を使用しましょう。
SSN は個人を一意に識別しますので、キーとして SSN を使用して顧客データを保管することは論理的です。(プライバシーの観点でよいアイデアであるかは別の問題であり、この記事の対象外です) 一方、名前で顧客を検索しなければならない場合は、正しいものが見つかるまでデータベース内のすべての SSN に対して反復処理を行わなければなりません。この方法による検索はとても遅いため、代わりにインデックスを使用するとよいでしょう。
"name" インデックスは一意ではないので、name に "Donna" が設定されている項目は複数存在する可能性があります。この場合は常に、キーの値がもっとも小さいものを取得します。
指定した name に該当するすべての項目にアクセスしなければならない場合は、カーソルを使用します。インデックス上で、2 種類のカーソルを開くことができます。ノーマルカーソルは、インデックスのプロパティと、オブジェクトストア内のオブジェクトを紐づけます。キーカーソルは、インデックスのプロパティと、オブジェクトストア内にオブジェクトを保存するために使用するキーを紐づけます。これらの違いを以下に示します。
カーソルで参照する値の範囲を制限したい場合は、IDBKeyRange オブジェクトを使用して、openCursor() または openKeyCursor() の第 1 引数として渡します。ひとつのキーのみ許可するキーレンジ、下限または上限の片方を持つキーレンジ、あるいは下限と上限の両方を持つキーレンジを作成できます。境界は "closed" (すなわち、キーレンジは指定した値を含む) または "open" (すなわち、キーレンジは指定した値を含まない) のどちらにもできます。使い方を以下に示します。
昇順 (すべてのカーソルのデフォルトの方向) ではなく、降順に反復処理を行いたい場合があるかもしれません。方向の切り替えは、openCursor() の第 2 引数に prev を渡すことで実現します。
方向を変えたいだけで表示する結果は制限しない場合は、第 1 引数に null を渡します。
"name" インデックスは一意ではありませんので、name が同じ項目が複数存在する可能性があります。キーは常に一意でなければならないため、オブジェクトストアでこのような状況は発生できないことに注意してください。インデックスに対して反復処理を行う際に重複を取り除きたい場合は、方向の引数に nextunique (逆向きであれば prevunique) を指定します。nextunique または prevunique を使用すると、常にキーが最小の項目が返ります。
有効な方向の引数については、「IDBCursor 定数」をご覧ください。
データベースのバージョン変更が必要である場合に ウェブアプリでそのようなことを行うときは、ユーザーが古いバージョンの ウェブアプリをタブで開いている場合に別のタブで新しいバージョンのアプリを読み込んだときに発生することを考慮しなければなりません。データベースの実際のバージョンより大きなバージョンを指定して open() を呼び出すときは、データベースに変更を施す前に、他にデータベースを開いているものが明示的に要求を認めなければなりません (それらを閉じるか再読み込みするまで、onblocked イベントが発生します)。使い方を以下に示します。
すでに開かれているアプリが新たにデータベースを開こうとするコードを開始したが、古いバージョンのデータベースを使用している状況に対処するため、VersionError エラーもリッスンしましょう。
IndexedDB は同一生成元の原則を使用します。すなわち、ストアとサイトの生成元 (通常、サイトのドメインまたはサブドメイン) を紐づけますので、他の生成元からアクセスすることはできません。
サードパーティの window コンテンツ (例えば <iframe> のコンテンツ) は、ブラウザーがサードパーティ Cookie を禁止していない限り、自身が埋め込まれている生成元の IndexedDB ストアにアクセスできます(Firefox bug 1147821 をご覧ください)。
ブラウザーを終了するとき (例えばユーザーが「終了」や「閉じる」ボタンをクリックしたとき)、データベースを含むディスクは予期せず削除されたり、データベースストアへのパーミッションが失われたり、次のことが起きたりします。
上記の挙動は新しく、ブラウザーの Firefox 50、Google Chrome 31 以降 (おおよそ) のリリースで利用できます。
このバージョンのブラウザーの前は、トランザクションは暗黙裡に中断され、 close イベントが発行されず、予期せぬデータベースの停止を検出する方法はありませんでした。
ユーザーはいつでもブラウザーを終了することができますので、特定のトランザクションが完了することをあてにしたり、完了しなかったことを知ったりすることはできません。この動作が暗示することがいくつかあります。
第一に、データベースであらゆるトランザクションが終了したときに、常に一貫性がある状態を保つように注意するべきです。例えば、ユーザーが編集可能な項目のリストを保存する IndexedDB を使用していると想定します。オブジェクトストアを消去してから新たなリストを書き込むことにより、編集後のリストを保存します。あるトランザクションでオブジェクトストアを消去して、別のトランザクションで新たなリストを書き込むとすれば、消去した後かつ書き込む前にブラウザーが閉じられる危険性があり、その場合は空のデータベースが残ります。これを避けるために、消去と書き込みをひとつのトランザクションに結合しましょう。
第二に、データベースのトランザクションと unload イベントを紐づけるべきではありません。ブラウザーを閉じることで unload イベントが発生した場合、unload イベントハンドラーで作成したトランザクションは完了しません。ブラウザーのセッションにわたって情報を管理するための直感的な方法は、ブラウザー (または特定のページ) を開いたときに情報を読み込んで、ユーザーとブラウザーとの対話に応じて更新して、ブラウザー (またはページ) を閉じるときに保存する流れです。しかし、これは動作しないでしょう。データベースのトランザクションは unload イベントハンドラーで作成されますが、これらは非同期処理ですので、実行できるようになる前に中止されるでしょう。
実は通常のブラウザー終了であっても、IndexedDB のトランザクションが完了するよう保証する手段はありません。Firefox bug 870645 をご覧ください。通常の終了通知の回避策として、トランザクションの状況を追跡して、アンロード時にトランザクションが完了していないことをユーザーに警告するための beforeunload イベントを追加するとよいでしょう。
少なくとも中止通知と IDBDatabase.onclose を追加することで、いつ起こったのかがわかります。
IndexedDB API を使用した完全な例があります。この例では、出版物を格納し、取得するために IndexedDB を使用しています。
必要に応じて、より多くの情報を知るための記事集です。
This page was last modified on 2026年4月12日 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.