Chrome のメモリモードと省エネモードについてデベロッパーが知っておくべきこと

Chrome 108 では、メモリセーバーと省エネモードの 2 つの新しいモードが導入され、Chrome によるシステム リソースの使用状況をユーザーがより詳細に管理できるようになりました。

これらの新しいモードは主にユーザー向けのものですが、サイトのユーザー エクスペリエンスに影響を与える可能性があるため、ウェブ デベロッパーにとって注意すべき重要な意味があります。

この投稿では、これらの新しいモードがもたらす可能性のある影響と、最適なエクスペリエンスを実現するためにウェブ デベロッパーにできることについて説明します。

メモリセーバー モード

メモリセーバー モードを有効にすると、しばらくの間バックグラウンドで使用されていないタブが自動的に破棄されます。これにより、アクティブなタブや実行中の他のアプリケーションのためにメモリを解放できます。ユーザーは、特定のサイトのタブを破棄しないように Chrome に指示できますが、これはユーザーの設定であり、デベロッパーが制御することはできません。

タブを破棄すると、タブバーにタイトルとファビコンは引き続き表示されますが、タブを通常どおり閉じた場合と同様にページ自体は消えます。ユーザーがそのタブに再度アクセスすると、ページが自動的に再読み込みされます。

純粋なコンテンツ ページの場合、タブを破棄して再読み込みしてもユーザー エクスペリエンスに影響は生じないでしょう。しかし、複雑なユーザーフローを持つリッチでインタラクティブなサイトでは、ユーザーが中断した位置にページを復元できないと、フローの途中で再読み込みすると非常に不満になることがあります。

メモリを節約するためにタブを破棄する機能は、Chrome が長年にわたって行ってきたものですが、これはシステムにメモリの負荷がかかっている状況でのみ行われました。この問題は比較的まれであるため、ウェブ デベロッパーの皆様もその問題に気付いていない可能性があります。

Chrome 108 以降では、タブの破棄がより一般的になるため、サイトでこうした問題を適切に処理することが重要となります。

タブの破棄を処理するおすすめの方法

タブの破棄は、ウェブ デベロッパーにとって新しい課題ではありません。ユーザーが意図的に、または誤ってページを再読み込みすることは、タスクを完了する前に行われる可能性があります。そのため、ユーザーの状態を保存しておくことは、ユーザーがいったん離れた後、再び訪れた場合に復元できるようにしておくことが重要です。

最も重要な考慮事項は、ユーザーの状態を保存するかどうかではなく、いつ保存するかです。タブが破棄されたときに発生するイベントはないため、これは重要なことです。したがって、デベロッパーがそれに反応する方法はありません。むしろ、デベロッパーはこの可能性を予測し、前もって準備する必要があります。

ユーザーの状態を保存する最適なタイミングは次のとおりです。

  • 状態の変化に応じて定期的に実行。
  • タブがバックグラウンドで実行されている(visibilitychange イベント)とき。

状態を保存する最悪のタイミングは次のとおりです。

  • beforeunload イベント コールバック内。
  • unload イベント コールバック内。

これは、状態を保存する最悪のタイミングです。これらのイベントはまったく信頼性が低く、多くの場合(タブが破棄される場合など)発生しないためです。

ページのライフサイクル イベントの図では、ページが破棄されたときに発生することが想定されるイベントを確認できます。この図からわかるように、イベントを発生させることなく、タブが「非表示」状態から「破棄」状態になることがあります。

Page Lifecycle API の状態とイベントフロー。このドキュメントを通して説明される状態とイベントフローを視覚的に表した図。

実際、ページが「非表示」になっているときは、ページがブラウザによって破棄されるかユーザーによって終了される前に他のイベントが発生する保証はありません。そのため、保存していないユーザーの状態を常に visibilitychange イベントに保存することが重要です。

次のコードは、現在のユーザーの状態が変化したとき、またはユーザーがタブをバックグラウンドに移動したり、別のページに移動したりしたとき、すぐにキューに保持するロジックの例を示しています。

let state = {};
let hasUnstoredState = false;

function storeState() {
  if (hasUnstoredState) {
    // Store `state` to localStorage or IndexedDB...
  }
  hasUnstoredState = false;
}

export function updateState(newState) {
  state = newState;
  hasUnstoredState = true;
  requestIdleCallback(storeState);
}

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    storeState();
  }
});

タブの破棄の検出

前述のように、タブが破棄されようとしていることを検出することはできませんが、ユーザーが戻ってページを再読み込みした後にタブが破棄されたことは検出できます。このような場合、document.wasDiscarded プロパティは true になります。

if (document.wasDiscarded) {
  // The page was reloaded after a discard.
} else {
  // The page was not reloaded after a discard.
}

このような状況にユーザーが経験する頻度を把握するには、この情報を取得するように分析ツールを設定します。

たとえば、Google アナリティクスでは、カスタム イベント パラメータを設定して、タブが破棄されたページビューの割合を判断できます。

gtag('config', 'G-XXXXXXXXXX', {
  was_discarded: document.wasDiscarded,
});

分析プロバイダの方は、このディメンションを商品にデフォルトで追加することをおすすめします。

メモリセーバー モードでのサイトのテスト

ページを読み込み、別のタブまたはウィンドウで chrome://discards にアクセスすると、ページが破棄された際の処理をテストできます。

chrome://discards の UI で、破棄するタブをリストから見つけて、[アクション] 列の [緊急破棄] をクリックします。

破棄タブへのリンクの場所を示す chrome://discards UI のスクリーンショット

これにより、タブが破棄され、そのタブに再度アクセスして、ページを離れたときと同じ状態にページが再読み込みされたことを確認できます。

現時点では、webdriver や puppeteer などのテストツールを使用してタブの破棄を自動化する方法はありませんが、タブの破棄と復元はページの再読み込みとほぼ同じであるため、ユーザーフローの途中で再読み込み後にユーザーの状態が復元されることをテストすると、破棄/復元でも機能する可能性があります。この 2 つの主な違いは、タブが破棄されたときに beforeunloadpagehideunload イベントが呼び出されないことです。ユーザーの状態を保持するためにこれらのイベントに依存していない限り、再読み込みを使用して破棄/復元の動作をテストできます。

省エネモード

省エネモードを有効にすると、Chrome でディスプレイのリフレッシュ レートを下げることでバッテリーを節約し、スクロールやアニメーションの忠実度、動画のフレームレートに影響します。

一般的に、デベロッパーが省エネモードをサポートするために必要な操作はありません。このモードを有効にすると、ディスプレイのリフレッシュ レートの変化に応じて、アニメーション遷移requestAnimationFrame() の CSS API と JavaScript API が自動的に調整されます。

このモードが問題となる主なシナリオは、JavaScript ベースのアニメーションで、すべてのユーザーに対して特定のリフレッシュ レートを想定している場合です。

たとえば、サイトで requestAnimationFrame() ループを使用していて、コールバック間の経過時間がちょうど 16.67 ミリ秒であると仮定した場合、省エネモードが有効になっていると、アニメーションの実行速度は 2 倍遅くなります。

なお、すべてのユーザーに対してデフォルトのリフレッシュ レートを 60 Hz と想定することは、現行のデバイスの多くには当てはまらないため、デベロッパーにとって常に問題となっていました。

ディスプレイのリフレッシュ レートの測定

ディスプレイのリフレッシュ レートを測定する専用のウェブ API はないため、通常、現在の API で測定することはおすすめしません

既存の API で最善の対処法は、連続する requestAnimationFrame() コールバックのタイムスタンプを比較することです。ほとんどの場合、この処理は特定の時点でのリフレッシュ レートの概算になりますが、リフレッシュ レートがいつ変更されたかはわかりません。そのためには、常に requestAnimationFrame() アンケートを実行する必要があります。これにより、ユーザーのエネルギーやバッテリーの節約という目標が達成できなくなります。

省エネモードでサイトをテストする

省エネモードになっているサイトをテストする方法の 1 つは、Chrome の設定でこのモードを有効にして、デバイスが電源に接続されていないときに動作するように設定することです。

電源から外せるデバイスがない場合は、次の手順で手動でこのモードを有効にすることもできます。

  1. chrome://flags/#battery-saver-mode-available フラグを有効にします。
  2. chrome://discards にアクセスして、[バッテリー セーバー モードを切り替え] リンクをクリックします(重要: リンクを機能させるには、#battery-saver-mode-available フラグを有効にする必要があります)。

省エネモードを有効にするリンクの場所を示す chrome://discards UI のスクリーンショット

有効にすると、サイトを操作して、アニメーションや遷移が希望の速度で実行されるなど、すべてが想定どおりに表示されることを確認できます。

まとめ

Chrome のメモリセーバー モードと省エネモードは主にユーザー向けの機能ですが、適切に処理しないとサイトへのアクセスに悪影響を及ぼす可能性があるため、デベロッパーにとっては影響があります。

一般に、これらの新しいモードはデベロッパー向けの既存のベスト プラクティスを念頭に置いて設計されています。ウェブに関する長年のベスト プラクティスに従っていれば、サイトはこれらの新しいモードでも問題なく動作するはずです。

ただし、この投稿で紹介した対策がサイトに含まれている場合、ユーザーがこの 2 つのモードを有効にした場合のみ、問題が増える可能性があります。

これまでと同様に、エクスペリエンスが優れていることを確認する最善の方法は、ユーザーの条件と一致する条件でサイトをテストすることです。