#14「フロントエンドにおけるキャッシュ戦略」

オフライン対応や、表示速度向上には欠かせない、Service Workerのキャッシュ機能をどう活用していくか、というお話をしました。Cloudflare Workersについても少しお話ししています。

古川
こんにちは!
加藤
こんにちは!
古川
ミツエーテックラジオは株式会社ミツエーリンクスのスタッフがWebデザイン、WebフロントエンドなどのWeb技術に関するニュースやツールなどをシェアしたりするためのPodcastです。司会は古川が務めさせていただきます。今回のゲストは設計チームの加藤くんです。よろしくお願いします!
加藤
よろしくお願いします!
古川
今回は、「フロントエンドにおけるキャッシュ戦略」というテーマで話していきたいと思います!
加藤
はい。キャッシュ戦略といっても現金のcashではなくて、情報をためていく方のcacheなので、ご注意いただければと思います。
古川
はーい(笑)
最近のキャッシュに関連する業界の変化だと、「オフライン対応しているか」つまりキャッシュがされているかどうかによってGoogle ChromeにおけるPWAのインストール要件が変わるってニュースがありましたね。
加藤
そうですね。以前はService Workerにfetchイベントが定義されてさえいればイベントハンドラーの中身が空であってもインストールできていたんですけど、今後はmanifest.jsonのstart_urlで定義されたページへのリクエストに対してオフライン状態で200レスポンスを返すことが、PWAインストールを可能にするための必須要件になるようです。
古川
これっていままでのPWA要件では、オフラインのときに返すリソースがない場合ってどうなってるんでしたっけ。
加藤
Chromeでおなじみの恐竜のページが表示されます。
古川
あー、あのキーボードで恐竜でジャンプしてゲームできるページですね。
加藤
そうですね。PWAはユーザーによりよいUXを提供できるアプリケーションを目指してるんですけど、このアップデートはPWAのコンセプトの「信頼性」って部分に焦点を当てたものかなと思います。ネットワークの状況によらず安定してアプリケーションを使用できるっていうのは、ユーザーから一種の信頼を得るためには大事なポイントとなるかなーと思います。
古川
その電車に乗っているときとかたまにインターネットが不安定になったりするんですけど、そのタイミングでオフラインになってアプリケーションが使えないとたまにイラッとしますもんね。
加藤
そうですね。オフライン対応によって得られることって、その名の通りネットワークがなくてもコンテンツを見られるというところばっかりに目が行きがちなんですけど、オフライン対応の実態ってService WorkerのCache APIを利用してリクエストに対するレスポンスをブラウザ内部にキャッシュすることなので、まぁオフラインじゃなくても画面表示が高速化されたりとか、通信が発生しないことでエネルギー消費を減らせたりとか、オンラインのときでも受けられる恩恵ってのはたくさんあるんですよね。
古川
たしかにキャッシュって、PWAとかオフライン対応のためのものでしょ!とか一括りにしちゃうと「うちはオフライン対応はしなくてもいいや」みたいに思ってしまう人がいるかもしれないですね。コーポレートサイトでService Workerによるキャッシュを導入しているケースってまだ多くない印象なんですけど、その辺りのイメージのしづらさが普及を妨げてるんですかね?
加藤
それもあると思いますね。あとは、キャッシュ戦略を決める難しさっていうのも1つの要因かなぁと思います。
古川
なるほど。今回のPWAのアップデートをふまえると、キャッシュ戦略についてもこのタイミングでしっかりおさえておいた方がよさそうですね。
加藤
そうですね。今回のアップデートされたインストール要件を満たすためにstart_urlに該当するページだけオフラインにするっていうよりは、これを機にサイトやアプリ全体のキャッシュ戦略を決めてみるのもいいなぁと思います。
古川
キャッシュ戦略っていろんな考え方があると思うんですけど、どういう決め方がいいんですかね?
加藤
代表的なところだとWorkboxっていうGoogleが提供しているPWA用の便利ツールみたいなものがあって、そのツールの公式サイトの中で「Workbox Strategies」っていうページがあって、その中でいくつか戦略が挙げられています。
古川
あー、あのStale-While-RevalidateとCache FirstとNetwork FirstとNetwork OnlyとCache Onlyですね?
加藤
そうですね。いま古川さんがあげてくれたのは「どうキャッシュするか」っていう視点の戦略ですね。他にもいろいろ視点があって、昔古川さんがミツエーリンクスのフロントエンドBlogに書いていた「Request.destinationでリソースの種類別にキャッシュ戦略」という記事にある通り、リソースの種類別にキャッシュすること、つまり「何をキャッシュするか」っていう視点もありますね。なので、キャッシュ戦略を組み立てるときは基本的にこういう視点を組み合わせて、どのリソースにはどの戦略を採用するか、というところを考えていくことになると思います。
古川
難しそうですね…。リソースの種別が同じであっても、コンテンツの性質によっては戦略を変える必要があったりしそうですよね。たとえばリソースの種別が「image」であってもこっちの画像はキャッシュファーストで、こっちの画像はネットワークファーストみたいな。あとはキャッシュするにしても、どのくらいの期間キャッシュするかも決める必要がありそうな感じがします。
加藤
おっしゃる通りですね。まぁこういういろんな視点で戦略を組み立てる必要があるっていうところがキャッシュの難しいところだなぁと思います。
時間に限りがあるので今回はすべて紹介しないんですけども、ここからは先ほどのWorkbox Strategiesの中からいくつかの戦略をピックアップしてみようと思います。
古川
お願いします!
加藤
はい。まずはStale-While-Revalidateパターンですね。これのコンセプトはHTTPヘッダーとしてのStale-While-Revalidateを指定したときの動きと似ていて、それをService Workerで再現するっていうイメージですね。大まかにいえばキャッシュが利用可能であれば、キャッシュしたコンテンツを表示するんですけど、同時に最新データのフェッチも行って、裏側ではキャッシュを更新しておくと。で、次回のアクセスからは最新のデータが表示されるようになるっていうイメージですね。
古川
キャッシュによる高速化と、フェッチによるデータの最新化、両方を行ってるってことですね。
加藤
そうですね。このパターンの良いところはキャッシュを活用しつつ、新しい情報を取得できるっていう点ですね。ただリアルタイムには更新しないので、たとえばユーザーが設定したアバターの画像とか、まぁそこまで即時性は高くないけど、できるなら比較的早めにアップデートされてほしいという温度感のコンテンツが使い所です。
古川
キャッシュを扱う上で、ほんとは更新されてほしかったのにされてない、みたいなのはキャッシュあるあるですよね。でもこれだとよいバランスが取れそうです。
加藤
そうですね。
続いて、Cache Firstです。Cache Firstはキャッシュを利用できる場合はキャッシュを、利用できない場合はネットワークからフェッチする、っていうわりと直感的なパターンですね。CSSやJavaScriptのライブラリなど、更新頻度がそれほど高くないものについてはCache Firstが向いているケースが多いかなと思います。
で、逆に即時性が求められたりとか、頻繁に更新するようなもの、たとえばニュースリリースなどの記事コンテンツだったり、SNSのタイムラインはNetwork Firstが向いていますね。Network Firstは基本的に最新の情報をフェッチしますが、サーバが落ちてたりとか、レスポンスに時間がかかってしまう場合は、キャッシュに切り替えるっていうパターンです。
古川
やっぱり、なんでもかんでもキャッシュするのではなくて、動的にデータを取得するコンテンツみたいな、オンラインであることが前提であるコンテンツについてはいっそキャッシュしない、つまりNetwork Onlyみたいなパターンもありますよね。中途半端に古いコンテンツを表示するよりは、オフラインであることや、うまくデータを取得できなかったことをユーザーに伝えるほうがUXとしては良い場合もありそうな感じがしました。
加藤
そうですね。あると思います。
古川
うーん、なるほど…。やっぱりこう、聞いた感じ考えることが山積みですね。ここまでいろいろなキャッシュ戦略について話してきたんですけど、戦略を決めるにあたって注意すべきことって何かありますかね?
加藤
まず技術的な観点でいうと、キャッシュはあくまでユーザーのデバイスに保存されるっていうこと、そしてこのストレージの容量はほかのLocal StorageだったりIndexedDBなどと共有されていること、最後にブラウザ側でキャッシュストレージを勝手に削除してしまうこともあるっていうことですかね。
古川
なるほど、場合によってはこちらが意図しないキャッシュの振る舞いになるかもしれないってことですよね。やっぱり扱いがむずかしいですね…、研究が必要です。
加藤
うん、そうですね。あとは先ほどの話と少し被ってしまうのですけど、やっぱりWebサイトで提供している情報の性質に見合った戦略を選ぶことってのがまずは大事かなぁと思います。たとえば、Stale-While-Revalidateについていえば、最新のデータのフェッチが完了するまでは古いキャッシュデータが表示されてしまうので、それが適切かどうかというのも合わせて考慮する必要がありますね。
古川
なるほど。なにか具体例とかあげられますか?
加藤
たとえば災害情報を掲載しているWebサイトとかはキャッシュによって古い情報が表示されてしまったら人の命に関わる危険性もあるので、表示パフォーマンスも大事なんですけど、最新の情報を正確に提供する必要がありますよね。
古川
なるほど。確かにWebサイト単位でとりあえずキャッシュだ!とか、あとはキャッシュは不安だから全部ネットワークファーストだ!というゼロイチ的な発想じゃなくて、このリソースは変更頻度が低いからキャッシュのほうがいいとか、あとはこの情報は最新であることが大事だからネットワークオンリーじゃなきゃいけないよねー、とかそういう決め方をしないといけないですね。
加藤
その通りだと思いますね。まぁ、それが難しいっていう話なんですけどね。
古川
まぁそうですね(笑)
今日はキャッシュについて語ってきたんですけど、今後のキャッシュ戦略はどうなりそうでしょうか。
加藤
Stale-While-Revalidateパターンは、 多くの一般的なWebサイトに適用できるバランス重視型の戦略なので、比較的選択されやすいのかなーと思ってます。とくに即時性が必要なケースでなければ、初めの一歩として導入するのはいいかもしれないなーと思いますね。
あとは最近といってもここ1、2年なんですけど、Cloudflare Workersっていうネットワークのエッジで動くService Workerみたいなものも出てきています。で、今「みたいなもの」と言ったのはService Workerそのものではなくて、Service Workerのインターフェイスに似てるJavaScriptが実行できるっていう意味ですね。
古川
Cloudflare Workersだとなにができるんですか?
加藤
いろいろ機能はあるんですけど、大雑把にいえばService Workerがブラウザ上でやっていた一部のこと、たとえばキャッシュだったりとか、ルーティングだったりをエッジでできるっていう感じですね。Service Workerの場合はあくまでユーザーのブラウザ内部で動いているので、キャッシュがたまるのはそのユーザーのブラウザの中だけになるんですけど、Cloudflare Workersはエッジで動いてるので、キャッシュもエッジに保存されていくんですよね。なので、同じエッジを経由するすべてのユーザがそのキャッシュの恩恵を受けることができると。ただ、もちろんエッジまでのネットワークは必要になってしまうので、完全にオフラインでは見れなくなってしまいます。
古川
へーなるほど…。キャッシュ戦略の候補のひとつとしてあがりそうですね。
加藤
そうですね。まぁただ若干フロントエンドから片足はみ出してる感じがありますし、あくまで候補の1つと捉えておくのがいいと思います!
古川
なるほどです。がんばってキャッチアップしていきたいと思います!
加藤
はい!
古川
ということで最後に、ミツエーリンクスではスマートなコミュニケーションをデザインしたいUIデザイナー、UI開発者の募集をしています。採用サイトではオンライン説明会やオンライン面接なども行っていますのでぜひチェックしてみてください。
また、このPodcastはApple Podcast、 Google Podcast、Spotifyで配信しています。お好みのプラットフォームでフォローいただけると、最新のエピソードをすぐ視聴できます!こちらもぜひご活用ください。
それでは今日はこの辺で!ありがとうございましたー!
加藤
ありがとうございましたー!