ページライフサイクル

ドラフトコミュニティグループレポート,

このバージョン:
https://wicg.github.io/page-lifecycle/
課題管理:
GitHub
編集者:
(Google)
以前の編集者:
(Google)
(Google)

概要

本ドキュメントは、ブラウザがウェブページのライフサイクルを管理する能力をサポートするAPIを定義します。

この文書のステータス

この仕様は Web Platform Incubator Community Group によって公開されました。 W3C標準でもW3C標準化トラック上のものでもありません。 W3C Community Contributor License Agreement (CLA) のもと、限定的なオプトアウトや他の条件が適用されることにご注意ください。 W3Cコミュニティおよびビジネスグループについて詳しくは、こちらをご覧ください。

1. はじめに

多数のWebアプリ(およびタブ)が動作していると、メモリ・CPU・バッテリー・ネットワークなどの重要なリソースがすぐに使い過ぎとなり、ユーザー体験が悪化します。アプリケーションのライフサイクルは、現代のOSがリソースを管理する主要な手法です。

プラットフォームがアプリケーションライフサイクルをサポートするには、以下が必要です:

この提案は、Webページのライフサイクルが何かを定義し、Webアプリケーションがユーザーエージェントによってよく行われる2つの重要なライフサイクルイベントに応答できる拡張を追加することを目指しています:

2. ページライフサイクル状態

この仕様はWebページのライフサイクルが何かを定義し、Webアプリケーションがユーザーエージェントによってよく行われる2つの重要なライフサイクルイベントに応答できる拡張を追加します:

この仕様では、上記をサポートするために2つの新しいライフサイクル状態を正式化します:

TODO(panicker): 図を挿入予定

3. API

ページライフサイクルには以下の追加が含まれます:

partial interface Document {
    attribute EventHandler onfreeze;
    attribute EventHandler onresume;
    readonly attribute boolean wasDiscarded;
};

onfreezeonresume 属性は、それぞれ freeze および resume イベントの イベントハンドラーIDL属性です。

wasDiscarded 属性のgetterは、この Documentdiscarded ブール値を返します。

注: これらのAPIは Document に追加されています。 Window ではなく、 Page Visibility APIとの一貫性のためです。これらのAPIは既存APIと組み合わせて使われることを想定しています。[PAGE-VISIBILITY]

注: 加えて clientId および discardedClientIdWindow に追加され、破棄後にページを再訪してリロードする際のビュー状態復元をサポートします。これらは本イベントに反応するコードで利用される見込みです。

3.1. 使用例

freezeとresumeのハンドリング例:

const prepareForFreeze = () => {
  // 開いているIndexedDB接続を閉じる。
  // Webロックを解放する。
  // タイマーやポーリングを停止する。
};

const reInitializeApp = () => {
  // IndexedDB接続を復元する。
  // 必要なWebロックを再取得する。
  // タイマーやポーリングを再開する。
};

document.addEventListener('freeze', prepareForFreeze);
document.addEventListener('resume', reInitializeApp);

破棄後にビュー状態を復元する例: ユーザーが同じアプリ・URLで複数タブを開いている場合、両方がバックグラウンドかつ破棄されたとき、アプリは2つのタブを区別して正しい状態を復元する必要があります。この目的でWindowのclientIdとlastClientIdが使えます。

// IndexedDBに状態を保存する際、self.clientIdの現在値をレコードにセットしておくことで
// getPersistedState()で後から取得可能(タブが破棄後リロードされた場合など)。
const persistState = async (state) => {
  const record = {...state, cliendId: self.clientId};

  // レコードをIndexedDBやSessionStorageに保存...
}

// 渡されたクライアントIDに基づき、IndexedDBから状態レコードを取得。
const getPersistedState = async (clientId) => {
  // IndexedDBでレコードを検索...
};

// タブが以前破棄されていれば、self.lastClientId経由でそのクライアントIDの状態を取得。
if (document.wasDiscarded) {
  getPersistedState(self.lastClientId);
}

4. 機能ポリシー

ネストされた閲覧コンテキスト の実行状態を制御することは、閲覧コンテキストからユーザー体験を管理する上で望ましいです。たとえばアプリケーションは、ドキュメントが 描画中でない、または ビューポートに重なっていない場合、 ネストされた閲覧コンテキスト内(再生中の動画や音声含む)のすべての実行を停止したいかもしれません。すべての実行を停止することでCPU利用効率が向上します。こうしたニーズに対応するため、2つの機能ポリシーを定義します:

"execution-while-not-rendered" ポリシーは、 ネストされた閲覧コンテキスト閲覧コンテキストコンテナ描画中でない場合に、タスクの実行可否を制御します。

"execution-while-out-of-viewport" ポリシーは、 ネストされた閲覧コンテキスト閲覧コンテキストコンテナビューポートに重なっていない場合(ターゲット要素とルートの交差領域計算アルゴリズムによる)に、タスクの実行可否を制御します。

§ 5.2 HTML標準の修正では、以下条件を満たした際にドキュメント(およびその子孫)を凍結状態に移行することでこれを実現します:

これら条件が成立しない場合、ドキュメントは未凍結状態となります。

<!-- iframeはロード後すぐに凍結されます。 -->

<iframe allow="execution-while-not-rendered 'none'"
  src="subframe.html" style="display:none"></iframe>
Document documentドキュメント凍結状態更新手順は以下の通り:
  1. document閲覧コンテキストネストされた閲覧コンテキストでない場合はreturn。

  2. documentreadiness が "complete" でない場合はreturn。

  3. elementdocument閲覧コンテキスト閲覧コンテキストコンテナとする。

  4. frozenness を false とする。

  5. auto resume media を false とする。

  6. document が "execution-while-not-rendered" 機能の利用を許可されていない場合:

    1. element描画中でなければ frozenness を true にする。

  7. それ以外で document が "execution-while-out-of-viewport" 機能の利用を許可されていない場合:

    1. elementビューポートに重ならない場合(ターゲット要素とルートの交差領域計算による)、 frozenness を true、auto resume media を true にする。

  8. frozennessdocument凍結状態と異なる場合、 ドキュメントの凍結状態変更document, frozenness, auto resume media)を実行。

5. 処理モデル

5.1. ワークレット・ワーカーの挙動変更

単一の ワークレットエージェントrealmグローバルオブジェクト所有ドキュメント凍結状態の場合、進行停止となる必要があります。 単一の 専用ワーカーエージェントrealmグローバルオブジェクト所有ドキュメントが非nullかつ 凍結状態の場合も 進行停止となる必要があります。

DedicatedWorkerGlobalScope workerGlobalScope所有ドキュメント判定手順:
  1. workerGlobalScope所有セットが1つの Document document なら、document を返す。

  2. workerGlobalScope所有セットが1つの DedicatedWorkerGlobalScope parentWorkerGlobalScope なら、parentWorkerGlobalScope所有ドキュメント を返す。

  3. nullを返す。

注: DedicatedWorkerGlobalScope所有セットは常に1つだけ要素を持ちます。

5.2. HTML標準の修正

5.2.1. ドキュメントのアンロード履歴トラバーサル

ドキュメントが bfcache(back forward cache) へ出入りする際、凍結状態がtrue/falseに遷移します。

5.2.2. イベントループ: 定義

置き換え: タスクは、その document がnullまたは 完全にアクティブな場合、実行可能。

修正後: タスクは、その document がnullまたは 完全にアクティブかつ 未凍結の場合、実行可能。

5.2.3. イベントループ: 処理モデル

レンダリングの更新中、Step #11後に以下のステップを追加:

完全にアクティブDocument doc それぞれについて、ドキュメント凍結状態更新手順docで実行。

5.2.4. 閲覧コンテキストの破棄

閲覧コンテキストやドキュメントの「discard」概念を「destroy」にリネームします。これにより、ユーザー向け属性 wasDiscarded に「discarded」という用語を使えます。

5.2.5. ドキュメントの初期化

Step #3の前に以下を追加:

閲覧コンテキストが以前破棄状態だった場合、Documentdiscardedブール値をtrueにセット。

5.2.6. iframe loadイベントの手順

Step #5後に以下を追加:

child documentドキュメント凍結状態更新手順を実行。

5.2.7. HTMLMediaElement

HTMLMediaElementresume frozen flag(初期値false)を持ちます。

5.2.8. メッセージの送信

注記追加:

注: 凍結状態の Window にメッセージ送信すると、posted message task sourceにキューされたイベントは Window未凍結になるまで実行されません。 イベントが多すぎる場合、ユーザーエージェントは Window閲覧コンテキストを破棄することがあります(リソース圧迫時の一般的な破棄許可の一部)。

5.3. Service Worker標準への修正

5.3.1. Client

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

enum ClientLifecycleState {
    "active",
    "frozen"
};

Client オブジェクトは ライフサイクル状態 を持ち、これは ClientLifecycleState 列挙値のいずれかです。

5.3.1.1. lifecycleState

lifecycleState のgetter手順は、thisライフサイクル状態を返します。

5.3.1.2. matchAll(options)

Step #4 の変数名を変更します。

  1. matchedClientData を新しい リストとする。

Step #2.5.1 の前に挿入

  1. lifecycleStateGet Client Lifecycle Stateclient を渡して実行した結果とする。

Step #5.3.1 でリストに lifecycleState を追加

  1. windowData を «[ "client" → client, "ancestorOriginsList" → 新しい リスト, "lifecycleState" → lifecycleState ]»とする。

Step #5.4 で matchedClientData に lifecycleState を追加

  1. «[ "client" → client, "lifecycleState" → lifecycleState ]» を matchedClientData に追加する。

Step #6.2 で windowData の lifecycleState を Create Window Clientアルゴリズムに渡す

  1. windowClientCreate Window Clientアルゴリズムに windowData["client"], windowData["frameType"], windowData["visibilityState"], windowData["focusState"], windowData["ancestorOriginsList"], windowData["lifecycleState"] を引数として渡して実行した結果とする。

Step #6.3 の調整

  1. clientDatamatchedClientData で反復:

    1. clientObjectCreate Clientアルゴリズムに clientData["client"], clientData["lifecycleState"] を引数として渡して実行した結果とする。

    2. clientObject を clientObjects に追加する。

5.3.1.3. openWindow(url)

Step #7.5 の前に挿入

  1. lifecycleStateGet Client Lifecycle Statethis の関連 service worker client を渡して実行した結果とする。

Step #7.8.2 の調整(lifecycleState を渡す)

  1. clientCreate Window ClientnewContextWindow オブジェクトの environment settings object, frameType, visibilityState, focusState, ancestorOriginsList, lifecycleState を引数として実行した結果とする。

5.3.2. アルゴリズム

5.3.2.1. クライアントのライフサイクル状態取得

次のアルゴリズムを追加:

入力

client : service worker client

出力

state : 文字列

  1. state"active" にする。

  2. もし clientglobal object所有ドキュメント凍結状態なら state"frozen" にする。

  3. state を返す。

5.3.2.2. Create Client

入力に lifecycleState(文字列)を追加

出力の Step #2 の後に次を追加

  1. clientObjectライフサイクル状態lifecycleState にセットする。

5.3.2.3. Create Window Client

入力に lifecycleState(文字列)を追加

出力の Step #5 の後に次を追加

  1. windowClientライフサイクル状態lifecycleState にセットする。

5.4. ページライフサイクル処理モデル

5.4.1. 凍結状態(FROZENNESS state)

ドキュメントは以下の 凍結状態(FROZENNESS) のいずれかになります:

UAは状況に応じ トップレベルドキュメントの凍結状態変更アルゴリズムをtrueで実行することがあります。 例えば、トップレベル閲覧コンテキストがバックグラウンドまたは非表示であり、猶予期間が経過した場合、UAはリソース節約とフォアグラウンドのユーザー体験品質維持のためtrueで実行できます。 具体例:

UAは通常、ユーザーがその閲覧コンテキストを再訪した際 トップレベルドキュメントの凍結状態変更をfalseで実行します。また、リソースが豊富にある場合はバックグラウンドでも定期的にfalseで実行することがあります。

5.4.2. ドキュメントの凍結状態変更

トップレベルドキュメントの凍結状態変更Document topLevelDoc、boolean frozenness状態frozenness)の手順:
  1. Assert: doc閲覧コンテキストトップレベル閲覧コンテキストである。

  2. ドキュメントの凍結状態変更topLevelDoc, frozenness, false で実行。

  3. descendants子孫閲覧コンテキストのリストdoc)とする。

  4. 閲覧コンテキスト bdescendants で反復:

    1. descendantDocumentアクティブドキュメントb)とする。

    2. ドキュメントの凍結状態変更descendantDocument, frozenness, false で実行。

ドキュメントの凍結状態変更Document doc, boolean frozenness状態frozenness, boolean auto resume frozen media)の手順:
  1. もし frozenness が true なら freeze stepsdocauto resume frozen media で実行。

  2. そうでなければ resume stepsdoc で実行。

freeze stepsDocument doc, boolean auto resume frozen media)の手順:
  1. doc凍結状態 を true にセットする。

  2. freezeイベントを doc で発火する。

  3. elementsメディア要素のうち shadow-including descendantsdoc をルートとし、shadow-including tree orderで並べたものとする。

  4. elementelements で反復:

    1. もし elementpaused が false なら:

      1. elementresume frozen flagauto resume frozen media にセットする。

      2. media pauseelement に実行。

    注: frozenness 状態の代入がイベント発火より先になる順序は意図的です。

resume stepsDocument doc)の手順:
  1. elementsメディア要素のうち shadow-including descendantsdoc をルートとし、shadow-including tree orderで並べたものとする。

    1. elementelements で反復:

      1. もし elementsresume frozen flag が true なら:

        1. elementsresume frozen flag を false にセット。

        2. media playelement に実行。

  2. resumeイベントを doc で発火する。

  3. doc凍結状態 を false にセットする。

    注: frozenness 状態の代入がイベント発火の後になる順序は意図的です。

5.4.3. 破棄(Discarding)

各Documentは discarded ブール値(初期値false)を持つ。

discard で閲覧コンテキストを破棄するには、閲覧コンテキストをdestroyし、その理由がdiscardingによるものであることを記録する(子孫も同様)。

注: discardは通常、システムメモリ等のリソース不足時に解放目的で行う。一方destroyはユーザーがページ離脱等で通常の後処理として行う。

閲覧コンテキスト ― バックグラウンドかつ、そのドキュメントが VisibilityState hidden の場合、リソース圧迫時(例:メモリ不足)には discarded され得る。具体例:

トップレベル閲覧コンテキスト(ブラウザのタブ)がリソース圧迫や予期せぬ事象(プロセスクラッシュ等)で 破棄された後、ユーザーが再度タブを訪れた場合、Documentdiscarded ブール値が § 5.2.5 ドキュメントの初期化により true となります。

6. 謝辞

この仕様の改善につながる技術的な助言と提案をいただいた Dave Tapuska、 Fadi Meawad、 Ojan Vafai、 Olli Pettay、 Philip Walton、 そして Todd Reifsteck に特別な感謝を捧げます。

適合性

文書規約

適合性要件は記述的な断言と RFC 2119 の用語の組み合わせで表現されています。 この文書の規範部分における「MUST」「MUST NOT」「REQUIRED」「SHALL」「SHALL NOT」「SHOULD」「SHOULD NOT」「RECOMMENDED」「MAY」「OPTIONAL」といったキーワードは RFC 2119 の定義に従って解釈されます。 ただし、可読性のため、これらの語はすべて大文字では記載されていません。

この仕様のすべての文章は、 明示的に非規範とされた節・例・注記を除き、規範的です。[RFC2119]

この仕様の例は「for example」という語で始めるか、規範テキストと区別して class="example" が付与されて示されます。 例:

これは情報例の一例です。

情報注記は「Note」で始まり、規範テキストと区別して class="note" が付与されて示されます。 例:

注: これは情報注記の例です。

適合アルゴリズム

アルゴリズムの一部として命令形で書かれた要件(例:「先頭の空白文字を除去する」や「falseを返してこれらの手順を中止する」)は、アルゴリズム導入部で使われているキーワード("must"、"should"、"may" など)の意味で解釈されます。

アルゴリズムや特定の手順として表現された適合要件は、最終的な結果が同等であれば、どのような方法で実装してもかまいません。 特に、この仕様で定義されたアルゴリズムは理解しやすいことを意図しており、パフォーマンスを重視したものではありません。 実装者は最適化を推奨します。

索引

本仕様で定義された用語

参照で定義される用語

参考文献

規範的参考文献

[CSS21]
Bert Bos; 他. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. URL: https://drafts.csswg.org/css2/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; 他. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SERVICE-WORKERS-1]
Alex Russell; 他. Service Workers 1. URL: https://w3c.github.io/ServiceWorker/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

参考情報

[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 2013年10月29日. REC. URL: https://www.w3.org/TR/page-visibility/

IDL索引

partial interface Document {
    attribute EventHandler onfreeze;
    attribute EventHandler onresume;
    readonly attribute boolean wasDiscarded;
};

partial interface Client {
    readonly attribute ClientLifecycleState lifecycleState;
};

enum ClientLifecycleState {
    "active",
    "frozen"
};