対応ブラウザ
最新のブラウザでは、ページが停止されたり、完全に破棄されたりすることがあります。 システム リソースに制約があります。将来的にはブラウザでも同じことが求められるようになります。 そのため、消費電力やメモリも少なくなります。Page Lifecycle API ライフサイクル フックにより、ページでこうしたブラウザを安全に処理できます。 介入することで、ユーザー エクスペリエンスは損なわれません。API を確認し アプリに実装すべきかどうかを確認できます
背景
アプリケーションのライフサイクルは、現代のオペレーティング システムが 説明します。Android、iOS、および最近の Windows バージョンでは、 OS によりいつでも停止できます。これによりこれらのプラットフォームでは ユーザーに最もメリットがある場所にリソースを再割り当てします。
ウェブにはこれまでそのようなライフサイクルは存在せず、アプリを保持したままで 無期限に存続します。多数のウェブページが実行されているため、 メモリ、CPU、バッテリー、ネットワークなどのリソースはオーバーサブスクライブできます。 エンドユーザーエクスペリエンスの 低下につながります
一方、ウェブ プラットフォームには以前から、ライフサイクルの状態に関連するイベントがありました。
(load
など)
unload
、
visibilitychange
— これらのイベントはデベロッパーのみが
ライフサイクルの状態の変化に対応できるようにしています。ウェブを効果的に利用する
低電力のデバイス上でも確実に稼働できます(また、リソースへの
すべてのプラットフォーム)ブラウザでは、事前にシステムを再利用して再割り当てする方法が必要
説明します。
実際、今日のブラウザはすでにリソースを節約するための積極的な対策を講じている 多くのブラウザ(特に Chrome)では、 より多くのことを行い、全体的なリソース フットプリントを削減することです。
問題は、開発者がこの種の攻撃に備える方法がないことです。 システムによって開始された介入や、それが起こっていることを認識している可能性もあります。つまり ブラウザには保守的なものを使用する必要があり、そうしないとウェブページが壊れるリスクがあります。
Page Lifecycle API さまざまな方法を試しています。
- ウェブでのライフサイクルの状態のコンセプトを導入し、標準化しています。
- システムによって開始される新しい状態を定義し、ブラウザが新しい状態を 非表示のタブやアクティブでないタブで消費される可能性があるリソースです。
- ウェブ デベロッパーが対応できるようにする新しい API やイベントを作成する これらの新しい状態への遷移や、システムが開始した状態からの遷移についても考慮する必要があります。
このソリューションは、ウェブ デベロッパーが アプリケーションへの復元力が高く、ブラウザでより多くの システム リソースを積極的に最適化し、最終的にすべてのウェブ ユーザーに利益をもたらす。
この投稿の残りの部分では、新しいページ ライフサイクル機能をご紹介します。 既存のウェブ プラットフォームの状態とそれらがどのように関連しているかを調べる 作成できます。また、Terraform ワークフローの各タイプに関する推奨事項とベスト プラクティスも 各州で開発者が行うべき(およびすべきでない)作業の割合。
ページのライフサイクルの状態とイベントの概要
ページ ライフサイクルのすべての状態は離散的で相互に排他的です。つまり、 状態は一度に 1 つのみです。ページのライフサイクルの状態が変わっても 通常は DOM イベントを介して監視できます(例外については、各状態に関するデベロッパー向けの推奨事項をご覧ください)。
ページのライフサイクルの状態を説明する最も簡単な方法と、 イベント間の遷移を示すイベントを図で説明します。
<ph type="x-smartling-placeholder">州
次の表に、各状態の詳細を示します。また、発生し得るデータの イベントの発生前と後の状態のほか、デベロッパーが モニタリングに使用できます。
州 | 説明 |
---|---|
有効 |
ページが表示可能で、次のステータスがある場合、そのページはアクティブ状態です。 入力フォーカスです。
以前のステータスの例: |
パッシブ |
「パッシブ」状態とは、ページが表示され、表示されている場合 入力フォーカスがない場合もあります。
以前のステータスの例:
次のステータス: |
非表示 |
非表示のページは、非表示の状態で非表示の状態で (凍結、破棄、終了したコンテンツなど)。
以前のステータスの例:
次のステータス: |
フリーズ |
フリーズ状態では、ブラウザは以下の実行を一時停止します。
<ph type="x-smartling-placeholder"></ph>
凍結可能
ページの
タスクキューを維持します。たとえば
JavaScript タイマーとフェッチ コールバックは実行されません。すでに実行中
完了するまでに待機時間(最も重要なのは、
CPU/バッテリー/データ使用量を抑える手段として、ブラウザがページをフリーズします。 また、より迅速に <ph type="x-smartling-placeholder"></ph> 「戻る/進む」ナビゲーション - ページ全体を開かなくても大丈夫 再読み込みしてください。
以前のステータスの例:
次のステータス: |
終了 |
掲載を開始すると、ページは終了状態になります ブラウザによってメモリからアンロードおよびクリアされます。× <ph type="x-smartling-placeholder"></ph> 新しいタスクがこの状態で開始され、進行中のタスクが新しいタスクに 実行しすぎると強制終了されます。
以前のステータスの例:
次のステータス: |
破棄済み |
ページがアンロードされると、ページは discarded 状態になります。 リソースを節約できます。タスク、イベントのコールバック、 どんな種類の JavaScript でも、通常は破棄がこの状態で実行できます。 リソースの制約下で行われる。新しいプロセスの開始は、 不可能です タブ自体は、破棄状態で (タブのタイトルやファビコンを含む)は通常、ユーザーに表示されます。 そのページが消えてしまっても
以前のステータスの例:
次のステータス: |
イベント
ブラウザは多数のイベントをディスパッチしますが、 ページのライフサイクルの状態が変わる可能性がないかを確認します。次の表に、すべてのイベントの概要を示します。 ライフサイクルに関連するリストを作成し、遷移する可能性のある状態を列挙します。
名前 | 詳細 |
---|---|
focus
|
DOM 要素がフォーカスを受け取りました。
注:
以前のステータスの例:
考えられる現在の状態: |
blur
|
DOM 要素のフォーカスが失われました。
注:
以前のステータスの例:
考えられる現在の状態: |
visibilitychange
|
ドキュメントの
<ph type="x-smartling-placeholder"></ph>
|
<ph type="x-smartling-placeholder"></ph>
freeze
*
|
ページがフリーズしました。制限なし <ph type="x-smartling-placeholder"></ph> freezable タスクは開始されません。
以前のステータスの例:
考えられる現在の状態: |
<ph type="x-smartling-placeholder"></ph>
resume
*
|
ブラウザでフリーズしたページが再開されました。
以前のステータスの例: |
pageshow
|
セッション履歴エントリがトラバース中です。 まったく新しいページが読み込まれたり、
バックフォワード キャッシュ。ページが
バックフォワード キャッシュから取得された場合、イベントの
|
pagehide
|
セッション履歴エントリから走査されています。 ユーザーが別のページに移動していて、ブラウザがページの
現在のページを戻る/進む
後で再利用する場合、イベントの
以前のステータスの例:
考えられる現在の状態: |
beforeunload
|
ウィンドウ、ドキュメント、およびそのリソースがアンロードされます。 ドキュメントは引き続き表示され、この時点でも予定をキャンセルできます あります
重要:
以前のステータスの例:
考えられる現在の状態: |
unload
|
ページをアンロードしています。
警告:
以前のステータスの例:
考えられる現在の状態: |
* は、Page Lifecycle API で定義された新しいイベントを示します
Chrome 68 で追加される新機能
上のグラフは、2 つの状態を示しています。状態はシステムにより開始され、 ユーザー開始型: フリーズおよび破棄 前述のように、今日のブラウザは (独自の裁量により)表示されますが、デベロッパーが、 説明します。
Chrome 68 では、非表示のタブが凍結されていることや、
freeze
をリッスンすることでフリーズを解除する
document
の resume
イベント。
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
Chrome 68 以降、document
オブジェクトに
wasDiscarded
プロパティにアクセスする必要があります(Android のサポートはこの問題で追跡中です)。非表示の状態でページが破棄されたかどうかを確認する
タブを開くと、ページの読み込み時にこのプロパティの値を調べることができます(注:
破棄したページを再度使用するには再読み込みする必要があります)。
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
freeze
とresume
で行う重要なタスクに関するアドバイス
破棄されるページを処理して準備する方法については、
各州のデベロッパー向け推奨事項をご覧ください。
以降のセクションでは、これらの新機能が Google Cloud にどのように組み込まれるかについて 状態とイベントを定義します。
コードでページのライフサイクルの状態をモニタリングする方法
アクティブ、パッシブ、非表示 現在の状態を判別する JavaScript コードを実行できます。 既存のウェブ プラットフォーム API のページ ライフサイクルの状態。
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
VM でフリーズ状態と終了状態を
それぞれのイベントリスナーでのみ検出できます。
(freeze
と pagehide
)。
学びました。
状態変化を監視する方法
前に定義した getState()
関数に基づいて、すべてのページを監視できます。
ライフサイクルの状態は、次のコードで変わります。
// Stores the initial state using the `getState()` function (defined above).
let state = getState();
// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
const prevState = state;
if (nextState !== prevState) {
console.log(`State change: ${prevState} >>> ${nextState}`);
state = nextState;
}
};
// Options used for all event listeners.
const opts = {capture: true};
// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
window.addEventListener(type, () => logStateChange(getState()), opts);
});
// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
// In the freeze event, the next state is always frozen.
logStateChange('frozen');
}, opts);
window.addEventListener('pagehide', (event) => {
// If the event's persisted property is `true` the page is about
// to enter the back/forward cache, which is also in the frozen state.
// If the event's persisted property is not `true` the page is
// about to be unloaded.
logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);
このコードは、次の 3 つのことを行います。
getState()
関数を使用して初期状態を設定します。- 次の状態を受け取り、変更があれば 状態変更がコンソールに記録されます。
- 追加
捕捉する
イベント リスナーが用意され、必要に応じてライフサイクル イベントが
logStateChange()
になり、次の状態を渡します。
コードについて注意すべき点は、すべてのイベント リスナーが追加されている点です。
window
に到達し、これらはすべて合格
{capture: true}
。
これには次のような理由があります。
- すべてのページ ライフサイクル イベントに同じターゲットがあるわけではありません。
pagehide
、およびwindow
に対してpageshow
が発行されます。visibilitychange
、freeze
、resume
はdocument
に、focus
とblur
は 各 DOM 要素です。 - これらのイベントのほとんどはバブルを発生させないため、 イベント リスナーを共通の祖先要素に関連付けて、 できます。
- キャプチャ フェーズは、ターゲット フェーズまたはバブルフェーズの前に実行されるので、 他のコードでキャンセルされる前に確実に実行されるようにできます。
各州におけるデベロッパー向けの推奨事項
デベロッパーとして、ページのライフサイクルの状態と、 コード内でモニタリングする方法を学んでください。 ページの状態に大きく依存します。
たとえば、一時的な通知を表示するのは明らかに意味がありません。 表示されなくなります。これはわかりやすい例ですが 明らかに、それほど明白ではないものの、 列挙します。
州 | デベロッパー向けの推奨事項 |
---|---|
Active |
アクティブ状態はユーザーにとって最も重要な時間であるため、 ページがクリックされやすいタイミングを <ph type="x-smartling-placeholder"></ph> ユーザー入力にすばやく反応できます。 メインスレッドをブロックする可能性のある UI 以外の処理は、優先度を下げる必要があります。 宛先<ph type="x-smartling-placeholder"></ph> アイドル時間または ウェブワーカーにオフロードできます |
Passive |
パッシブ状態では、ユーザーはページを操作していません。 見ることができますつまり、UI の更新とアニメーションは、 更新が行われるタイミングはそれほど重要ではありません。 ページがアクティブからパッシブに変わると、 保存されていないアプリケーション状態を保持するのに適した時間です。 |
ページがパッシブから非表示に変わると、 再読み込みするまで、ユーザーは再度操作できない可能性があります。 非表示への移行は、多くの場合、最後の状態変化でもあります。
(これは特に
ユーザーがタブやブラウザアプリ自体を閉じることができるようになり、
つまり、隠れた状態を、隠れた状態への終わりとして扱い、 表示されます。つまり、保存されていないアプリケーションの状態を保持する 未送信の分析データがある場合は UI の更新も停止する( 停止し、ユーザーが望ましくないタスクはすべて停止します。 バックグラウンドで実行されています。 |
|
Frozen |
固定状態では、 <ph type="x-smartling-placeholder"></ph> タスクキューは、ページのフリーズを解除するまで一時停止され、 発生することはありません(ページが破棄された場合など)。 ページが非表示から固定に変わると、 タイマーを停止したり接続を解除したりして 同じオリジンで開いている他のタブや ページを バックフォワード キャッシュを使用します。 特に、次のことが重要になります。
また、動的ビューの状態(スクロール位置など)も保持する必要があります。
表示)を
<ph type="x-smartling-placeholder"></ph>
ページが固定から非表示に戻る場合、 閉じた接続を再開したり、ポーリングを再開したりして、 停止されました。 |
Terminated |
通常、ページが移行しても特に操作を行う必要はありません。 終了状態にします。 ユーザーの操作によってアンロードされたページは常に 終了ステータスに入る前に、非表示状態を 非表示状態は、セッション終了ロジック( アプリケーションの状態の維持や分析への報告など)は、 確認できます。 また、このセクションの推奨事項
非表示状態)が維持されるようにするためには、
終了状態への遷移を確実に行うことができないことを
多くのケース(特にモバイル)で検出されるため、
解除イベント時(例: |
Discarded |
discarded 状態は、 ページが破棄される時間です。これは、ページは通常、 リソースの制約のもとで破棄される、または レスポンスとして実行するスクリプトを単純にモデルに 使用できます。 そのため、コンテナが破棄される可能性に備えて
非表示から固定に変更し、変更を
ページの読み込み時に破棄されたページの復元に
|
繰り返しになりますが、ライフサイクル イベントの信頼性と順序付けは すべてのブラウザに一貫して実装されているため、 使用する際は、 PageLifecycle.js。
以前のライフサイクル API で
次のイベントはできる限り避ける必要があります。
unload イベント
多くのデベロッパーは unload
イベントを保証されたコールバックとして扱い、
状態を保存して分析データを送信するためのセッション終了シグナルですが、
特にモバイルでは、まったく信頼できないunload
イベントは行われません。
多くの一般的なアンロード状況で発生します(タブからタブを閉じる場合など)。
ブラウザ スイッチャーを使用するか、アプリ スイッチャーからブラウザアプリを閉じます。
このため、常に
visibilitychange
イベントを使用して、セッションがいつ終了したかを
隠れ状態を考えてみましょう。
アプリとユーザーデータを保存する信頼性の高い最後の期間。
さらに、登録済みの unload
イベント ハンドラが存在する場合(
onunload
または addEventListener()
など)のいずれか)を指定すると、ブラウザが
ページをバックフォワード キャッシュに入れて、
前方と後方の負荷に対応できます
最新のブラウザでは、常に
pagehide
イベントを検出して、ページ アンロード(
終了状態)を unload
イベントではなく、もし
Internet Explorer のバージョン 10 以前をサポートしている場合は、
pagehide
イベントを検出し、ブラウザがサポートしていない場合にのみ unload
を使用します。
pagehide
:
const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
window.addEventListener(terminationEvent, (event) => {
// Note: if the browser is able to cache the page, `event.persisted`
// is `true`, and the state is frozen rather than terminated.
});
beforeunload イベント
beforeunload
イベントにも unload
イベントと同様の問題があります。
これまでは、beforeunload
イベントが存在する場合は、ページからページが表示されなくなる可能性が
バックフォワード キャッシュの対象になります。最新のブラウザ
この制限はありません。ただし ブラウザによっては
ページを「バックフォワード」に移動しようとしたときに beforeunload
イベントが発生した
つまり、イベントはセッション終了シグナルとして信頼できません。
また、一部のブラウザ(Chrome を含む)
beforeunload
イベントを許可する前にページでのユーザー操作が必要である
起動し、さらにその信頼性に影響を及ぼします。
beforeunload
と unload
の違いの一つは、
beforeunload
の正当な使用について Google が確認します。たとえば、ユーザーに警告を
ページのアンロードを続行すると、ユーザーは変更内容を保存できなくなります。
beforeunload
を使用する正当な理由があるため、次のことをおすすめします。
ユーザーが変更を保存していない場合にのみ、beforeunload
リスナーを追加します。
削除することもできます。
つまり、この操作はしないでください(beforeunload
リスナーが追加されるため)。
(無条件):
addEventListener('beforeunload', (event) => {
// A function that returns `true` if the page has unsaved changes.
if (pageHasUnsavedChanges()) {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
}
});
代わりに次のようにすることをおすすめします(これは、呼び出されたときにのみ beforeunload
リスナーを追加するからです)。
必要でなければ削除):
const beforeUnloadListener = (event) => {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
};
// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
addEventListener('beforeunload', beforeUnloadListener);
});
// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
removeEventListener('beforeunload', beforeUnloadListener);
});
よくある質問
「読み込み中」が表示されない理由どうでしょうか。
Page Lifecycle API は、互いに独立して相互に排他的な状態を定義します。 ページはアクティブ、パッシブ、非表示のいずれかの状態で読み込まれるため、 読み込みが完了する前に状態を変更したり終了したりすることがあるため、 個別の読み込み状態は、このパラダイムでは意味をなしません。
ページが非表示のときにも機能しますが、固定または破棄されないようにするにはどうすればよいですか?
実行中にウェブページを凍結してはならない正当な理由はたくさんあります 隠れ状態にします。最もわかりやすい例は、音楽を再生するアプリです。
また、Chrome がページを破棄することはリスクの高い
未送信のユーザー入力があるフォームや
ページがアンロードされたときに警告する beforeunload
ハンドラ。
当面の Chrome では、ページを破棄する際の保守性と ユーザーに影響しないことが確実な場合にのみ行ってください。たとえば 隠れ状態では次のことは行いませんが、 リソースの制約が厳しい場合を除いて、破棄されます。
- 音声の再生中
- WebRTC の使用
- 表のタイトルまたはファビコンの更新
- アラートの表示
- プッシュ通知の送信
タブが安全かどうかを判断するために使用される現在のリスト機能 詳細は、冷凍および廃棄物のヒューリスティクス破棄しています できます。
バックフォワード キャッシュは、 一部のブラウザでは、ナビゲーションの最適化機能を実装しています。 進むことができます。
ユーザーがページから離脱すると、これらのブラウザでは、そのバージョンのページがフリーズします。
そうしてユーザーが戻ってきた場合にすぐに再開できるように
戻るボタンや進むボタンを押すだけです。なお、unload
を追加する際は、
イベント ハンドラにより、この最適化ができなくなります。
意図と目的によれば、このフリーズは ブラウザのフリーズは CPU とバッテリーを節約するために機能します。理由があります。 ライフサイクル状態は「凍結」の一部と見なされます。
フリーズ状態または終了状態で非同期 API を実行できない場合、IndexedDB にデータを保存するにはどうすればよいですか?
凍結状態や終了状態では 固定可能なタスク ページのタスクキュー内 つまり、IndexedDB のような非同期のコールバック ベースの API が一時停止されます。 信頼性に欠ける可能性があります
将来的には、IDBTransaction
オブジェクトに commit()
メソッドを追加する予定です。これにより、
実質的に書き込み専用トランザクションを開発者が実行できるようにする
コールバックを必要としないサービスを提供しています。言い換えると、開発者がコードを書くだけで
データを IndexedDB に書き込み、読み取りで構成される複雑なトランザクションを実行しない
タスクキューが解放される前に、commit()
メソッドを終了できます。
一時停止します(IndexedDB データベースがすでに開いていることを前提としています)。
しかし、現時点で機能する必要があるコードについては、次の 2 つの選択肢があります。
- セッション ストレージを使用: セッション ストレージ 同期され、ページが破棄されても保持されます。
- Service Worker から IndexedDB を使用する: Service Worker でデータを
ページが終了または破棄された後の IndexedDB。
freeze
またはpagehide
イベント リスナー: 以下を使用して Service Worker にデータを送信できます。postMessage()
, Service Worker がデータの保存を処理できます。
フリーズ状態と破棄状態でのアプリのテスト
フリーズ状態と破棄状態でのアプリの動作をテストするには、
chrome://discards
を使用して、実際の
クリックします。
![Chrome の UI の破棄](https://developer.chrome.google.cn/static/docs/web-platform/page-lifecycle-api/image/chrome-discards-ui-4c0620d6f8619.png?authuser=6&hl=ja)
これにより、ページで freeze
と resume
を正しく処理できるようになります。
イベントと document.wasDiscarded
フラグ(その後にページが再読み込みされた場合)
破棄します。
概要
ユーザーのデバイスのシステム リソースを尊重したいデベロッパー ページのライフサイクルの状態を念頭に置いてアプリを構築する必要があります。重要なのは ウェブページがシステム リソースを過剰に消費していない 想定外の結果になるのは
新しい Page Lifecycle API の実装を開始するデベロッパーが増えるほど、API の安全性が高まります。 ブラウザが使用していないページを凍結して破棄しますこの ブラウザのメモリ、CPU、電池、ネットワーク リソースの消費量が少なくなるため、 これはユーザーにとってのメリットです