最近仕事で、よくフロントエンド側の実装に問題があり、それがユーザの不便につながらトラブルに遭遇しました。
問題が顕在化しなければ見過ごされていましたが、どうやらリロードすると永続化していないVuexのストアが消えることに気づいていなかったようです。で、関係者に話したところ、ストアってなに?っていうかlocalstorageとか使えばいいの?っていうかそれもよくわかんないんだけど、みたいな感じでした。
ということで、自分の理解も兼ねて整理することにしました。
フロントエンド側でデータを保持する方法
次のような方法があります(他にもあるかもしれません)
- LocalStorage
- SessionStorage
- indexedDB(WebSQL)
- Session Cookie
- Persistent Cookie
- JavaScript変数
- Vuex・Redux等
- Service Worker
- Server Side Session
まとめ
結論次のとおりです。
技術要素 | 書き込み先 | データの寿命 | 有効期限のバリエーション |
---|---|---|---|
JavaScript変数 | クライアント: メモリ | タブを閉じたとき | – |
LocalStorage | クライアント: ディスク | ユーザが削除するまで | その他 (基本的に期限なし、ただし手動で削除は可能) |
SessionStorage | クライアント: ディスク | タブを閉じたとき | – |
indexedDB | クライアント: ディスク | ユーザが削除するまで | その他 (基本的に期限なし、ただし手動で削除は可能) |
WebSQL (※非推奨) | クライアント: ディスク | ユーザが削除するまで | その他 (基本的に期限なし、ただし手動で削除は可能) |
Session Cookie | クライアント: ディスク | ブラウザを閉じたとき | セッションの有効期限 |
Persistent Cookie | クライアント: ディスク | 有効期限が訪れたとき | 指定の日時、または時間が経過したとき |
Vuex・Redux等 | クライアント: メモリ | タブを閉じたとき | – |
Service Worker | クライアント: ディスク/メモリ | 独自のライフサイクル | その他 (Service Workerの更新ポリシーや、キャッシュの期限に依存) |
Server Side Session | サーバ: メモリ/ディスク | 有効期限が訪れたとき | セッションの有効期限, あるいは指定の日時 |
なりたち
私はナラティブにすると覚えやすいと思ったので、一部想像も入るので注意ですが、エポックメイキングだと思ったことを独断と偏見で次のように語ってみます。
JavaScript変数
初めはきっと、全部、JavaScript変数を用いて必要なデータを保持していました。それはそうですよねたぶん。
Cookieの登場
JavaScript変数はメモリ領域に保存されるゆえに、ページ遷移やリロードによって消えてしまいます。これだと、例えば会員制のサイトにログインした場合に、ページ遷移の度に認証が必要になってしまいます。そこで、セッションという概念が登場します。
Session Cookieを利用して、一度認証したらタブを閉じるまで再認証することなくページ遷移する体験を提供できるようになります。そのうえで、Persistant Cookieを選択することで、タブを閉じてもユーザのお気に入りレシピなど、よく利用する情報を保存・参照し、手間を削減することができるようになります。
Sessionの登場
さて、Cookieによってパーソナルなデータが便利に扱えるようになりましたが、カバーしきれない不便なケースが出てきます。例えば、ECサイトにおける購買です。Aさんがカートに入れた商品をBさんがカートに入れて先に購入完了してしまった場合、Aさんは購入できないというがっかり体験が発生しうるのです。これを解決する方法として、セッションが登場します。セッションによってサーバサイドへユーザの情報を管理することで、Bさんがそもそもカートに入れられないようにして、Aさんのがっかり体験を防止することができます。その他にも、認証の有効期限をサーバサイドで管理することで、一貫性のある状態管理ができるようになります。そのように、一連のリクエスト/応答の流れを識別するための仕組みがSessionです。
LocalStorageとかの登場
ここまでで、ページを跨いでも必要な値を管理する方法が充実してきましたが、2009年代にもなるとPCの普及率は50%を余裕で超え、スマホが爆発的に普及し始める兆しが現れます。それと連動するように、Webでできること・求められることが拡大します。その中で、WebSQLやLocalStorageやindexedDBといったものが登場し、これまでCookieで行っていたような情報の管理方法がより拡張されました。
LocalStorage・SessionStorageによって、cookieよりも長い期間、より大きなサイズ(4KBを超えるサイズ)を扱えるようになり、例えばブラウザゲームのような大きなデータを頻繁に参照するようなユースケースに対応できるようになりました。
indexedDBの登場
また、WebSQLにより、構造化されたデータを扱うことができるようになったことで、JavaScriptによって一貫性のあるデータの取り扱いが容易になり、大規模なWebアプリ開発などがしやすくなりました。ただし、WebSQLはSQLiteをベースとした仕様であることもあり、Webにおける一般化に当たって様々な議論がなされた結果、最終的にindexedDBに取って代わられ非推奨となりました。
Service Workerの登場
その後、2015年になるとスマホ普及率は50%を突破し、スマホの携帯はメジャーなものとなりました。そうなってくると、あらゆる場所でWebコンテンツを参照したいニーズが生じてきます。例えば、電車での移動中にトンネルを通って瞬断されたとしても、コンテンツを使い続けられるようにしたいということになるのです。さらに、スマホとWebサーバはシームレスに連動し、サーバ側からの通知やオフラインでの動作やバックグラウンドでの動作といった機能のニーズも事業者が持ちます。この問題を解決するために、Service Workerが登場します。あ、ちなみにService Workerは2015年より少しから登場しています。
Service Workerはクライアント側からの要求と、サーバ側の応答の中間に位置し、ネットワークの状況に応じて適切な情報伝達を仲介します。これにより、あらゆるシーンでWebが利用できる、もしくはできないなりに最大限の機能をすることができるようになりました。
Vuex・Reduxの登場
ここまでで、ユーザがいつどんな場所からアクセスしても、混乱なく便利にWebサイトやWebアプリを利用することができる技術要素がそろってきました。ただ、どこまでいってもブラウザ上で動作するアプリという面では、ページ遷移などによるUXの悪さを逃れることはJavaScriptなしには難しいです。
そうなってくると、ほぼJavaScriptによってコンテンツの切り替え等を行うことを徹底することによって、ネイティブアプリ並みに軽快な動作ができるようなアプリを作成することが増えてきます。その用途に最適化されたアーキテクチャの一つにSPA等がありますが、SPA等による大規模なサービスの開発で利用されるのがVuex・Reduxなどの状態管理方法です。これらにより、大規模でも破綻しにくいようなコーディングができるようになり、ネイティブと比べて遜色ないようなパフォーマンスを発揮するアプリをブラウザ上から利用できるようになりました。