ローカルストレージに簡単な解決策はない

原文:“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 へのアクセスが多くなるに従い、より慎重に歩まなければならないのだろう。