bfcacheの基本とJavacSriptによる検知方法
bfcacheとは
bfcache は、back/forward cache の略で、ブラウザのキャッシュ機能のひとつです。
bfcache は、ウェブページの完全なスナップショットをJavaScriptの実行状況も含めてメモリに保存します。そして、ブラウザの戻るボタンや進むボタン(スマートフォンではスワイプによる戻る/進むも含む)によって、ページが遷移すると、そのページはメモリに保存された bfcache をもとに表示されます。ウェブページをネットワークを介してリクエストせずに表示できるため、高速にページを表示できます。
よく見かける例に、次のようなものが挙げられます。
スマートフォンサイトのドロワーメニューを開いた状態で、別のページに移動した後、スワイプして前のページに戻るとドロワーが開いたままになっている。
この現象は多くの場合 bfcache によってページが表示されているためだと考えられます。
こちらの動画もご覧ください。
bfcache が有効化どうかを確認する方法
Chromeのデベロッパーツールで、Application > Back/forward cache の画面に表示される test back/forward cache ボタンをクリックして、Successfully served from back/forward cache. と表示されれば、そのページは bfcache が有効になっている事を意味します。
bfcache の無効のページと、有効のページの、ページの表示のされ方を比較しましたので、以下の動画もご覧ください。
bfcache が有効の場合は、戻る/進むボタンでページを移動すると、ページ自体がリクエストされていない事が分かります。
なお、この動画は、Chromeのシークレットモードでキャプチャしています。
サポートしているブラウザ
bfcache は、元々はFirefoxやSafariでサポートされていた機能ですが、現在はChromeをはじめ主要なブラウザがサポートしているようです。
基本的には、 ページ内に unload イベントリスナーが存在する場合を除いて、bfcache は動作しないようですが、この挙動は各ブラウザによって異なります。
例えば、前述の動画で bfcache が無効だったページを、Firefoxで表示すると bfcache によってページが表示されている事が確認できます。
bfcache によるページ表示を検知して特定の処理を行う方法
bfcache を元にページが表示されると、JavaScriptも、そのページを離れた時点の段階から再開されます。オブジェクトの状態も保持されるようです。
そのため、ページロード時に必ず何らかの処理を行いたい場合などは、 bfcache を使ってほしくない時があります。
その場合は、 Cache-Control: no-store を適用する事で、ページが bfcache に保存されなくなります。
Cache-Control: no-store は 情報を HTTP cache に保存しないという指示で、 bfcache に対する指示ではないようですが、このHTTPヘッダーがセットされると、ブラウザは ページをbfcache に保存しないようにしてきたようです。そういう歴史があると、 web.dev の記事で紹介されていました。
詳しくはこちらの記事をご覧ください。
Source : Back/forward cache | Articles | web.dev
ただ、 私が経験した事例では、iOS Safariの場合は、 Cache-Control: no-store を適用したページでも bfcache が有効になっていました。そのため、iOSアプリのアプリ内ブラウザ(webview)でも同様の現象が起きていました。
この場合は、bfcache が有効な場合は、ページをリロードさせるという処理を行う事で対策を行いました。
bfcache が有効かどうかは、以下のコードでチェックします。
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// do something if page loaded from bfcache
}
});
persisted プロパティは、ページがキャッシュからロードされた場合に true を返すため、これを利用します。
なお、persisted プロパティについて、前述の web.dev では、bfcache からページが復元された場合に true を返すと書いてある一方で、 MDN では、単に、キャッシュからページがロードされている場合に true を返すと解説されていて、厳密に bfcache とは言及されていませんでした。
Source : PageTransitionEvent: persisted property - Web APIs | MDN
なお、(恐らく)Safari以外では Cache-Control: no-store がセットされていれば、 event.persisted は false になるため ifブロック 内のコードは実行されません。