IndexedDB vs localStorage:どちらのブラウザーストレージを使うか
IndexedDB vs localStorage
IndexedDB vs localStorage:容量、速度、使い分け | We.Inc
IndexedDBとlocalStorageを並べて比較します。ブラウザーごとの容量制限、同期と非同期、それぞれが保存できるもの、そして1つのメモを両方に保存するライブデモを紹介します。
少しの小さな設定ならlocalStorageを選びましょう。保存できるのは文字列のみで、オリジンごとに約5 MiB、すべての呼び出しが完了するまでページをブロックします。本格的なデータにはIndexedDBを選びましょう。非同期でトランザクションに対応し、オブジェクト、日付、ファイルを保存でき、容量はディスクの一定割合です。下のデモでは1つのメモを両方に書き込みます。
要点まとめ
- 何を保存できるか
- 文字列のみ
- 構造化複製アルゴリズムでコピーできるもの全般(BlobやFileを含む)
- 容量
- オリジンごとに最大5 MiB
- 空きディスクの一定割合(ブラウザーごとに決定)
- ページをブロックするか
- する。すべての呼び出しが同期的
- しない。結果はイベントかPromiseで届く
- Web Workerで使えるか
- 使えない。windowのプロパティのため
- 使える
- 最適な用途
- テーマ、最後に開いたタブ、下書きの文字列
- オフラインデータ、キャッシュ、ファイル、検索したいデータ全般
どちらのAPIも、タブを閉じた後も訪問者のブラウザーにデータを残し、どちらもページのオリジン単位で分けられます。違いは重さです。localStorageは1分で覚えられる小さな同期型の文字列マップで、IndexedDBはバージョン、オブジェクトストア、トランザクションを備えた小さなデータベースです。このページでは、ドキュメントに記載された実際の制限を示し、それぞれが何を返すかを実際に確認できます。
- メモを入力して「両方に保存」を押します。ページはlocalStorageにはJSONテキストとして、IndexedDBのオブジェクトストアには本物のオブジェクトとして書き込みます。
- 「読み戻す」を押します。結果パネルには各APIが返した型が表示されます。localStorageからは文字列、IndexedDBからは正しく動くDateを持つオブジェクトです。
- 「容量を確認」を押すと、navigator.storage.estimate()にこのオリジンの使用量と使用可能量を問い合わせます。数値は推定値です。
- 「デモデータを消去」を押すと、デモ用のキーを削除し、デモ用データベースを削除します。データがデバイスの外に出ることはありません。
- localStorage.setItemはtry...catchで囲みましょう。ストアが満杯だとQuotaExceededErrorが投げられ、一部のプライバシー設定では最初のアクセスでSecurityErrorが投げられます。
- localStorageにはJSON.stringifyの出力を保存し、読み込み時にパースしましょう。日付は文字列で戻ってくるので、自分で変換する必要があります。
- IndexedDBでは、idbやDexieのような小さなラッパーを使うと、リクエストとイベントの書き方をPromiseに変えられ、定型コードを大幅に減らせます。
- navigator.storage.persist()は、オフラインのドキュメントなど、失うと利用者が困るデータにだけ使いましょう。それ以外は、ストレージが逼迫したときにブラウザーが削除することがあります。
- どちらのストアにも秘密情報やセッショントークンを保存しないでください。ページ上で動くスクリプトなら誰でも読めてしまいます。
よくある質問
localStorageにはどれくらい保存できますか?
MDNでは、オリジンごとにlocal storageが5 MiB、session storageが5 MiB、合計10 MiBの制限と記載されています。値はUTF-16の文字列なので、収まる文字数は思ったより少なくなることがあります。制限を超えるとQuotaExceededErrorが投げられます。
IndexedDBにはどれくらい保存できますか?
ブラウザーとディスクによります。Chromium系ブラウザーでは、1つのオリジンがディスク全体の最大60%まで使えます。Firefoxのベストエフォートモードでは、ディスクの10%と、サイトグループごとの10 GiBのうち小さいほうです。Safariのブラウザーアプリではディスクの約60%です。実際の値はnavigator.storage.estimate()で確認しましょう。
IndexedDBはlocalStorageより速いですか?
ごく小さな値を1つ扱うだけなら、たいていlocalStorageのほうがコードを書くのも早く、実行速度も十分です。問題は同期的であることで、大きな読み書きはメインスレッドを止めてしまいます。IndexedDBはメインの処理の流れの外で作業し、完了したら知らせてくれるので、スクロールや入力がなめらかなままです。
ブラウザーがIndexedDBのデータを削除することはありますか?
あります。ストレージはデフォルトでベストエフォートなので、ディスクが逼迫するとブラウザーがオリジンのデータを削除することがあります。navigator.storage.persist()を要求すると永続モードに切り替わり、利用者本人しか消去できなくなります。Firefoxは許可を求めるプロンプトを表示し、ChromeとSafariは利用者のサイトの使い方から判断します。
ログイントークンにlocalStorageを使うべきですか?
いいえ。注入されたものを含め、ページ上のどのスクリプトもlocalStorageとIndexedDBを読めます。セッション識別子は、HttpOnly、Secure、SameSiteを付けたCookieに保存しましょう。ページのスクリプトからは読めません。
同期的であることがなぜ問題か
- コードがlocalStorage.getItemを呼ぶと、ブラウザーは値がディスクから戻るまで他のJavaScriptの実行を止めます。テーマ名程度なら誰も気づきません。しかし、ページを読み込むたびに数メガバイトのJSONをパースするなら、ページがタップに反応するまでの間として表れます。
- IndexedDBはすぐにリクエストオブジェクトを返し、後からsuccessかerrorを発火します。この形は書くコードが増えるため、多くのプロジェクトはPromiseのラッパーを使いますが、ページを人質に取ることは決してありません。
文字列と構造化複製
- localStorageはすべてをテキストに変換します。数値の3を保存すると文字列の "3" が戻り、JSON.stringifyを使わずにオブジェクトを保存すると "[object Object]" が戻ってきます。
- IndexedDBは構造化複製アルゴリズムで値をコピーするので、DateはDateのまま、MapはMapのまま残り、BlobやFileもそのまま保存できます。だからこそ、オフライン用の画像、録音した音声、添付ファイル付きの下書きに向いています。
選ぶためのシンプルなルール
- データが短い1行に収まり、起動時に1回読むだけなら、localStorageで十分です。検索したい、数えたい、ページ送りしたい、バイナリファイルを保存したい、Service Workerから更新したい、という場合はIndexedDBを使いましょう。
- 3つ目の選択肢として、多くの場合どちらよりも優れているのがサーバー側のデータです。利用者が別のデバイスでも同じものを見たいと期待するなら、そのデータはあなたのデータベースに置くべきで、ブラウザーのストアはキャッシュとしてだけ使います。
ブラウザー別のストレージ制限
数値はMDNのストレージ容量のページに記載されたものです。IndexedDB、Cache API、オリジンプライベートファイルシステムは同じ容量を共有します。
オリジンごとの容量
- ブラウザー
- localStorage
- IndexedDB(ベストエフォート)
- IndexedDB(永続)
- Chrome、Edge、その他のChromium
- 5 MiB
- ディスク全体の最大60%
- ディスク全体の最大60%
- Firefox
- 5 MiB
- ディスクの10%とサイトグループごとの10 GiBのうち小さいほう
- ディスクの最大50%(上限8 TiB)
- Safariブラウザーアプリ
- 5 MiB
- ディスク全体の約60%
- ディスク全体の約60%
- Webコンテンツを埋め込むアプリ(WebKit)
- 5 MiB
- ディスク全体の約15%
- ディスク全体の約15%
両方のAPIで同じ保存を行う
localStorage:文字列化、ガード、パース
try...catchはストアが満杯の場合やストレージがブロックされた場合に対応します。日付はパース後に手動で作り直す必要があります。
IndexedDB:開く、アップグレード、トランザクションで書き込む
onupgradeneededは初回と、バージョン番号が上がるたびに実行されます。オブジェクトストアを作れるのはここだけです。
空き容量を確認し、保持を要求する
estimate()はおおよそのバイト数を返します。persist()は、ブラウザーが永続ストレージを許可した場合にtrueで解決されます。
1つのメモを両方のストアに保存
このデモはあなたのブラウザー内だけで動きます。キーwe-demo-noteとデータベースwe-demo-dbに書き込み、消去ボタンで両方とも削除されます。
保存するメモ
金曜日に印刷会社へ電話する
両方に保存
読み戻す
容量を確認
デモデータを消去
まだ何も読み込んでいません。メモを保存してから「読み戻す」を押してください。
localStorageの戻り値
IndexedDBの戻り値
型:{v}
savedAtはDateか:{v}
何も保存されていません
メモをlocalStorageとIndexedDBに保存しました。
デモ用のキーとデータベースを削除しました。
このオリジンは、使用可能な約{v} MBのうち約{n} MBを使用しています。
このブラウザーはnavigator.storage.estimate()に対応していません。
このブラウザーでストレージ処理に失敗しました:{v}
無料で始める · クレジットカード不要
関連: ガイド|Webマーケティングと集客を学ぶ
製品
ご利用いただける方
機能
リソース
会社情報
サイトマップを見る