ローカルストレージに簡単な解決策はない
原文:“There is no simple solution for local storage” (on March 5, 2012 by Chris Heilmann)
要約:私たちは良いデータストアとして localStorage
を推奨するのをやめなければならない。パフォーマンスがひどく損なわれるからだ。しかし残念なことに、代わりとなるものはまだ完全にサポートされておらず、また簡単に実装できるものでもない。
Web 開発において、うますぎる話に出くわすことは常々だ。そういったもののいくつかは良いもので、だからこそそれが「すべて」として目立ってしまい、開発者を使うように仕向けてしまう。しかし、多くの場合、良いと思われていたものはそこまで良いものではない。また、しばらく使ってみてはじめて「間違っていた」と気づかされるものなのだ。
そんなもののひとつに、localStorage
がある。 (HTML5 として変に取り上げられることがとても多い) Web Storage 仕様はとてもシンプルな API を定義しており、仕様が公開された当初は Cookie キラーともてはやされていた。なんせ、ユーザーのマシンにデータを保存するにはただ navigator.localStorage
にアクセスすればよかったのだから (ブラウザのセッションを超えてデータを保持する必要がない場合には、sessionStorage
というものを利用すればよい)。
localStorage.setItem( 'outofsight', 'my data' ); console.log( localStorage.getItem( 'outofsight' ) ); // -> 'my data'
localStorage
は次の点で、Web 開発者にとってとても魅力的なものだった。
- 本当にシンプルだ
- ストレージに複雑なデータベースではなく、文字列を使用する (すこし複雑なデータには、JSON を使えばよい)
- ブラウザのサポートが進んでいる
- 多くのものが支持していた (そう、iPhone が初めて登場した時のような具合にだ)
いくつか課題もある。ストレージの上限に達した事を知るうまい仕組みがないこと、加えて、より多くの容量を求めるクロスブラウザな方法がないことだ。また、セッションや HTTPS についても隠れた課題があった。しかしこれらは、氷山の一角に過ぎないのだ。
重要な課題:ひどいパフォーマンス
localStorage
には、多くのdrawbackがある。そしてこれらは、ドキュメンテーションや巷の「HTML5 チュートリアル」にはあまり書かれることがない。パフォーマンスにシビアな開発者は、この API を使うことに強く反発している。
このブログ (訳註: Mozilla Hacks) で数週前に公開した画像とファイルを localStorage
に保存するという記事にはすごい数のコメントが寄せられた。また、localStorage
の悪さについて、さらにそれよりも長い議論が内部のメーリングリストで繰り広げられた。localStorage
が持つ主要な問題は次のとおりだ。
localStorage
は事実上同期的だ。つまり、ロードされているときに文書のレンダリングをブロックしてしまうlocalStorage
はファイルの I/O が絡む。つまり、ハードディスクに書き込みを行うため、システムによっては (インデックス作成やウイルススキャンなどで) 時間がかかることがある- 開発者のマシンでは OS がこうしたリクエストをキャッシュしてしまうため、問題が小さなものとみられてしまうが、エンドユーザは Web サイトロード時のブロックによって数秒待たされることになる
- 速く動いているように見せるため、ブラウザは最初のリクエスト時にデータをメモリ上にロードする ― つまり多くのタブを開くことで多くのメモリを食ってしまう
localStorage
は永続的なため、そのサイトやサービスをもう使わなくなっても、データがブラウザの立ち上げ時にロードされ続けてしまう
これらの問題は Mozilla パフォーマンスチームの Taras Glek によるポストや、Nokia の Andrea Giammarchi のポストによってより詳細に語られている。
要は、localStorage
でパフォーマンス向上と謳っている数多くの記事は、まったくもって間違っているということだ。
代替手段…
言うまでもなく、ブラウザはデータをローカルに保持する方法を提供してきた。知らないかもしれないが、evercookie なんてのがその例だ (強制的にキャッシュした PNG 画像を canvas で読むなんていう、誰が得しよう悪魔のささやきがいいじゃないか)。さて、Mozilla 内部での議論の中で、localStorage に代わって IndexedDB を推すという流れがあり、その結果 Mozilla Hacks に IndexedDB に画像とファイルを保存するという記事 が公開された。そして、いくつかの課題が浮かび上がってきた。多くは利便性と、ユーザのインタラクションに関わるものだ。
- IndexedDB は full-fledged DB で、SQL DB がデータを読み書きするステップを必要とする ― つまり
localStorage
が提供しているような、シンプルな key/value レイヤが存在しない - IndexedDB はユーザにデータを保存するかどうかを尋ねるため、ユーザがびっくりする可能性がある
- ブラウザのサポート状況が
localStorage
ほど良好ではなく、現在は IE10, Firefox, Chrome だけがサポートしているだけで、またその実装にも差異がある - Safari, Opera, iOS, Opera Mobile, Android Browser は WebSQL を支持している (WebSQL は別のデータベース仕様だが、W3C によって公式に非推奨とされた)
実装の差異があるなら、それを抽象化する仕組みを生み出す人がいる。Parashuram Narasimhan は jQuery プラグインまで提供するというすばらしいをした。しかし実装者としては複雑だ。これを使うしかないからだ。HTML5 video における WebM vs. H.264 という構図の繰り返しでしかないのだ。
どうする?
パフォーマンスの観点において、本物のデータベースを使うこと、非同期であることがより良いものであることは間違いない。また、これらは成熟しており、localStorage
ほど「短期的なハック」という感じもない。しかし一方で使いづらいという問題もある。localStorage
を利用したサイトはすでに数多く存在しているし、またユーザに許可を求めるということから UX という観点で受け付けられないことも想定される。
今言えることは、エンドユーザのマシンにデータを保存する仕組みにシンプルなものはないということ、だからこそパフォーマンス向上を謳った localStorage
の紹介はやめるべきということだ。これから我々がしなければならないのは、現在の実装を壊さず、みんなを幸せにする答えを見つけることだ。乗り越えるのは難しいかもしれない。ただ、アイデアはいくつか思いつく。
localStorage
を上書きし、IndexedDB/WebSQL に保存するという polyfill を開発するのはどうだろう。ダーティだし、ユーザに許可を求めるという問題は残ったままだ- 意図的な仕様違反のもと、
localStorage
を非同期的に実装するのはどうだろう。(危ない前例を作ることになるかもしれない) localStorage
の仕様を非同期に変更するのはどうだろう。また、適切なgetStorageSpace
インターフェースを持ち、さらにネイティブ JSON をサポートするように拡張するのはどうだろう- 各ブラウザベンダーが現在サポートしている API をマップする新しい API 仕様を定義するのはどうだろう
パフォーマンスを犠牲にしてまでローカルにデータを保存する。なんて意味のわからないことだろう。これは止める必要がある。この localStorage
は、新しい Web 標準が大きな力を授けてくれるのと同時に、それまで考えたこともなかった課題に直面するという好例だ。OS へのアクセスが多くなるに従い、より慎重に歩まなければならないのだろう。