1. はじめに
現代の Web アプリケーションは、ページ全体のナビゲーションを行うことなく、ユーザーインタラクションに応じて コンテンツを動的に更新することがよくあります。構造的な DOM の変更、コンテンツフルペイント、 履歴状態の変更など、これらのインタラクションによって開始された効果は、従来、測定し、 正しいユーザー操作に帰属させることが困難でした。
典型的なシングルページアプリケーションのパターンを考えてみます。ユーザーが商品リンクをクリックすると、click
イベントハンドラーが起動します。このハンドラーは、商品詳細のためのネットワーク fetch
を開始します。レスポンスが到着すると、
新しいコンテンツを DOM に動的に挿入し、History または Navigation API を使用して URL を更新する
コールバックが実行されます。ユーザーにはこれがナビゲーションのように見えますが、Largest Contentful Paint (LCP) ([LARGEST-CONTENTFUL-PAINT]) のような既存のメトリクスは初期ページ読み込みのみを測定し、
Interaction to Next Paint (INP) はクリック自体の直後の視覚的フィードバックのみを測定するため、
その後の重要なレンダリングおよび「ソフト」ナビゲーションは捕捉されません。
この仕様は、インタラクションを定義するために [EVENT-TIMING] API を活用し、非同期タスク境界を越えて因果関係を追跡するために [ASYNC-CONTEXT] 提案を活用します。これは、ブラウザーが「ソフトナビゲーション」を含むこれらの効果を識別して報告する方法を定義し、 [PAINT-TIMING] および [LARGEST-CONTENTFUL-PAINT] と統合することで、レンダリングの変更を パフォーマンスタイムラインに帰属させます。
さらに、この仕様は [CONTAINER-TIMING] 提案と統合します。 ユーザーインタラクションが DOM の変更を引き起こすと、それらの変更されたノードは新しい「コンテナールート」として指定されます。 それらのサブツリー内の後続のコンテンツフルペイントは、それぞれのルートに帰属され、 その後、元のインタラクションまで追跡されます。これにより、初期イベントディスパッチからかなり後に発生する、 リッチで動的なページ更新を効率的かつ正確に測定できます。
2. インタラクション基盤
2.1. ナビゲーション ID
navigation id は、global object の存続期間内の各ナビゲーション(ハードおよびソフトの両方)に割り当てられる一意な 識別子です。
各 global object は、current navigation
id、すなわち unsigned を持ち、初期値は
Document の initial interactionId value および Navigation Timing
の初期 navigationId を初期化する値と同じ値に設定されます。
2.2. インタラクションコンテキストの概要
この仕様は、この伝播を処理するために TC39 の [ASYNC-CONTEXT] 提案を活用します。すべての新しいユーザーインタラクション
(Event Timing によって定義されるもの)または関連するナビゲーションイベントは、新しい
InteractionContext を作成します。このコンテキストは、隠された内部専用の AsyncContext( と表記)に保存されます。
Web プラットフォームと AsyncContext の統合により、この変数は非同期継続(例: setTimeout、
fetch、)に自動的に
付加されるため、ブラウザーは後の効果を元のインタラクションに帰属させることができます。
スクリプトの伝播に加えて、この仕様は、DOM を変更するユーザーインタラクションが コンテナールート([CONTAINER-TIMING] 経由)を確立する方法を定義します。これらのルートにより、 コンテンツフルペイントのような後続のレンダリング効果は、現在アクティブな非同期スクリプトがない場合でも、 開始元のインタラクションコンテキストまで追跡できます。
2.3. InteractionContext 構造体
-
id、初期状態では未設定 - このコンテキストに関連付けられた interaction id。
-
start time、初期状態では未設定 - インタラクションの開始時刻を表します。
-
navigation type、初期状態では未設定 - ナビゲーションの種類(例: "push", "replace")を表します。
-
first URL value、初期状態では未設定 - 最初の変更時点の URL の値を表します。
-
first URL update timestamp、 初期状態では未設定 - このインタラクション中の最初の URL 変更時刻を表します。
-
first scroll timestamp、初期状態では未設定 - このインタラクション中の最初のスクロールイベントの時刻を表します。
-
first input timestamp、初期状態では未設定 - このインタラクション中の最初の入力イベントの時刻を表します。
-
first contentful paint、初期状態では null - このインタラクションの最初の
InteractionContentfulPaintエントリ。 -
largest contentful paint、初期状態では null - このインタラクションについてこれまでで最大の
InteractionContentfulPaintエントリ。 -
total painted area、初期状態では 0 - このインタラクションに帰属される すべてのコンテンツフルペイントの面積の合計。
-
last URL value、初期状態では未設定 - このインタラクション中の 最新の URL 変更の値を表します。
-
emitted フラグ、初期状態では false - インタラクションによって ソフトナビゲーションエントリが発行されたことを示します。
SoftNavigationEntry
の
name で first URL value のみが公開されている場合でも、効果をインタラクションの最終状態に正確に帰属させるために
内部的に追跡されます。
2.4. 基盤アルゴリズム
-
context を、内部
AsyncContext. Variableの値とします。[[ ActiveInteractionContext]] -
context を返します。
-
document の interaction id to interaction context[interaction id] が exists する場合、 document の interaction id to interaction context[interaction id] を返します。
-
interaction context を新しい InteractionContext とします。
-
interaction context の id を interaction id に設定します。
-
interaction context の start time を event の
startTimeに設定します。 -
document の interaction id to interaction context[interaction id] を interaction context に Set します。
-
interaction context を返します。
-
timestamp を、document の relevant global object が与えられた current high resolution time とします。
-
is scroll を、event の型が "scroll" の場合は true、そうでない場合は false とします。
-
is input を、event の型が([EVENT-TIMING] で定義される)has dispatched input event をトリガーするイベント型の場合は true、 そうでない場合は false とします。
-
is scroll が false かつ is input が false の場合、返します。
-
document の interaction id to interaction context の値の各 interaction context について:
-
is scroll が true で、interaction context の first scroll timestamp が 未設定の場合:
-
interaction context の first scroll timestamp を timestamp に設定します。
-
-
is input が true で、interaction context の first input timestamp が 未設定の場合:
-
interaction context の first input timestamp を timestamp に設定します。
-
-
-
interaction id が null の場合、null を返します。
-
interaction context を、document、interaction id、および event で get or create context for interaction を呼び出した結果とします。
-
内部
AsyncContext. Variableの値を interaction context に設定します。[[ ActiveInteractionContext]] -
interaction context を返します。
-
interaction context が null の場合、返します。
-
内部
AsyncContext. Variableの値を null に設定します。[[ ActiveInteractionContext]]
3. Interaction Contentful Paint
3.1. InteractionContentfulPaint インターフェイス
[Exposed =Window ]interface :InteractionContentfulPaint PerformanceEntry {readonly attribute DOMHighResTimeStamp ;renderTime readonly attribute DOMHighResTimeStamp ;loadTime readonly attribute unsigned long long ;size readonly attribute DOMString ;id readonly attribute DOMString ;url readonly attribute Element ?;element readonly attribute unsigned long long ;interactionId object (); };toJSON InteractionContentfulPaint includes PaintTimingMixin ;
各 InteractionContentfulPaint
は、関連付けられた paint timing info を持ちます。
renderTime
属性の getter は、this
に関連付けられた paint
timing info の rendering update end time を返さなければなりません。
loadTime
属性の getter は、this に関連付けられた paint
timing info の implementation-defined
presentation time を返さなければなりません。
size
属性の getter は、コンテンツフルペイントの size を返さなければなりません。
id
属性の getter は、コンテンツフルペイントの ID を返さなければなりません。
url
属性の getter は、コンテンツフルペイントの URL を返さなければなりません。
element
属性の getter は、コンテンツフルペイントに関連付けられた Element
を返さなければならず、その要素が文書から削除されている場合は null を返さなければなりません。
interactionId
属性の getter は、この paint を引き起こしたインタラクションの interaction
id を返さなければなりません。
3.2. Interaction Contentful Paint アルゴリズム
-
entry を、global の realm 内の新しい
InteractionContentfulPaintオブジェクトとします。 -
entry の
entryTypeを "interaction-contentful-paint" に設定します。 -
entry の
elementを element に設定します。 -
entry の
interactionIdを interaction context の id に設定します。 -
entry に関連付けられた paint timing info を新しい paint timing info に設定します。
-
entry の
renderTime、loadTime、size、id、 およびurlを、report largest contentful paint アルゴリズム ([LARGEST-CONTENTFUL-PAINT] 内で定義)のコンテンツフルペイント候補の対応する値に設定します。 -
entry の
startTimeを interaction context の start time に設定します。 -
entry の
durationを、entry のrenderTimeと entry のstartTimeの差に設定します。 -
entry を返します。
-
global を document の relevant global object とします。
-
paint entry を、global、interaction context、および element で create an interaction contentful paint entry を呼び出した結果とします。 注: リソース読み込みを必要とする要素(例: 新しい
srcを持つ画像)の場合、[PAINT-TIMING] 仕様は、最終的にこのアルゴリズムを呼び出す コンテンツフルペイント検出をトリガーする前に、"is loaded" 条件が満たされることを保証する責任を持ちます。 -
interaction context の first scroll timestamp が設定されており、 paint entry の
renderTimeが interaction context の first scroll timestamp より大きい場合、返します。 -
interaction context の first input timestamp が設定されており、 paint entry の
renderTimeが interaction context の first input timestamp より大きい場合、返します。 -
paint entry を Queue します。
-
paint entry を global の performance entry buffer に追加します。
-
interaction context の first contentful paint が null の場合:
-
interaction context の first contentful paint を paint entry に設定します。
-
-
interaction context の largest contentful paint を paint entry に設定します。
-
interaction context の total painted area を paint entry の size だけ増加させます。
InteractionContentfulPaint エントリは、インタラクションが最終的にソフト
ナビゲーションになるかどうかとは無関係に、検出された時点でパフォーマンス
タイムラインに発行されます。これにより、開発者はすべてのインタラクションのレンダリング更新を監視できます。
4. ソフトナビゲーション
4.1. SoftNavigationEntry インターフェイス
[Exposed =Window ]interface :SoftNavigationEntry PerformanceEntry {readonly attribute DOMString ;navigationType readonly attribute unsigned long long ;interactionId readonly attribute InteractionContentfulPaint ?; };largestInteractionContentfulPaint SoftNavigationEntry includes PaintTimingMixin ;
各 SoftNavigationEntry
は、関連付けられた paint timing info を持ちます。
navigationType
属性の getter は、ソフトナビゲーションを引き起こしたインタラクションの navigation type を返さなければなりません。
interactionId
属性の getter は、ソフトナビゲーションを引き起こしたインタラクションの interaction
id を返さなければなりません。
largestInteractionContentfulPaint
属性の getter は、そのインタラクションの結果として発生した最大のコンテンツフルペイントを表す InteractionContentfulPaint
エントリを返さなければならず、そのような paint が発生していない場合は null を返さなければなりません。
name
属性の getter は、ソフトナビゲーションを引き起こしたインタラクションの first URL
value を返さなければなりません。
startTime
属性の getter は、ソフトナビゲーションを引き起こしたインタラクションの start time を返さなければなりません。
duration
属性の getter は、発行時点の this の presentationTime
と this の
startTime
の差を返さなければなりません。
largestInteractionContentfulPaint
は non-null であることが期待されます。
ただし、将来の反復では、最初の paint より前に、URL 変更時点で直ちにソフトナビゲーションを committed とみなせるかどうかを評価する可能性があります。そのようなモデルでは、このフィールドは発行時点で null になる可能性があります。
このタイミングにおける主な設計上の考慮事項は、URL 変更と最初の paint の間の区間で発生する他のタイムラインエントリ
(例: LayoutShift、PerformanceResourceTiming、
LongAnimationFrameTiming など)の帰属です。たとえば多くのサイトは、
現在のページが以前のナビゲーション状態に残っている間でも、fetch リクエストを開始した直後に新しい URL を commit します。
一貫したタイムライン分割を保証するため、この仕様は、最初の paint が遷移を確認するまで、
そのようなすべてのエントリを以前のナビゲーション識別子に帰属させます。
4.2. ソフトナビゲーションアルゴリズム
soft navigation は、 次の条件を満たす同一文書ナビゲーションです:
-
InteractionContext がアクティブな間に、同一文書 URL 変更が発生する。
-
同じ InteractionContext に帰属されるコンテンツフルペイントが発生する。
-
interaction context の emitted が true の場合、返します。
-
document の active soft navigation candidate が interaction context でない場合、返します。
-
interaction context の first URL value が未設定の場合、返します。
-
interaction context の first contentful paint が null の場合、 返します。
-
global を document の relevant global object とします。
-
url を interaction context の first URL value とします。
-
entry を、global、interaction context、 url、および interaction context の start time で create a soft navigation entry を呼び出した結果とします。
-
global および entry で emit soft navigation entry を呼び出します。
-
interaction context の emitted を true に設定します。
DOMHighResTimeStamp
start time が与えられたとき、create a
soft navigation entry するには、次の手順を実行します:
-
entry を、global の realm 内の新しい
SoftNavigationEntryオブジェクトとします。 -
entry の
nameを url に設定します。 -
entry の
entryTypeを "soft-navigation" に設定します。 -
entry の
startTimeを start time に設定します。 -
first paint を interaction context の first contentful paint とします。
-
first paint が null でない場合:
-
entry に関連付けられた paint timing info を、first paint に 関連付けられた paint timing info に設定します。
-
-
entry の
interactionIdを interaction context の id に設定します(利用可能な場合)。 -
entry の
largestInteractionContentfulPaintを interaction context の largest contentful paint に設定します。 -
entry を返します。
navigationId は、さらに後の queue a PerformanceEntry で設定されます。
SoftNavigationEntry
entry が与えられたとき、emit soft
navigation entry するには、次の手順を実行します:
-
entry の navigation id を entry の
interactionIdに設定します。 -
global の current navigation id を entry の
interactionIdに設定します。 -
entry を Queue します。
-
entry を global の performance entry buffer に追加します。
-
interaction context を、get current interaction context を呼び出した結果とします。
-
interaction context が null の場合、返します。
-
interaction context の last URL value を url に設定します。
-
interaction context の first URL update timestamp が 未設定の場合:
-
interaction context の first URL update timestamp を、document の relevant global object が与えられた current high resolution time に設定します。
-
interaction context の first URL value を url に設定します。
-
interaction context の navigation type を navigation type に設定します。
-
-
document の active soft navigation candidate を interaction context に設定します。
-
document および interaction context で evaluate soft navigation emission を呼び出します。
5. PerformanceEntry 拡張
[Exposed =(Window ,Worker )]partial interface PerformanceEntry {readonly attribute unsigned long long ; };navigationId
PerformanceEntry
は、関連付けられた navigation id、すなわち unsigned long long を持ち、初期値は 0 です。
navigationId
属性の getter は、this の navigation id を返さなければなりません。
6. 仕様の統合
6.1. HTML 統合
6.1.1. Document
各 document は、interaction id to interaction context、すなわち map を持ち、初期状態では空です。
各 document は、active soft navigation candidate、すなわち InteractionContext または null を持ち、初期値は null です。
6.1.2. History
documentsEntryChanged が true であり、
documentIsNew が false の場合)の前に、
process same document commit を、Document、entry の url、および "traverse" で呼び出します。
6.1.3. Node
各 node は、associated interaction context を持ち、初期値は null です。
6.1.4. ハードナビゲーション
新しい global object global が作成されると(例: 「ハード」ナビゲーション中)、 その current navigation id は § 2.1 ナビゲーション ID で指定されるとおりに初期化されます。
PerformanceNavigationTiming
エントリを作成するとき、ユーザーエージェントはその navigationId を
global object の current
navigation id に設定しなければなりません。
6.2. Event Timing 統合
この仕様は、現代の Web アプリケーションおよびシングルページアプリケーションに関連する追加のイベント型を含めるために、 [EVENT-TIMING] のインタラクション定義を拡張します。
次のイベント型は、([EVENT-TIMING] で定義される)interaction の一部とみなされます:
-
navigate -
popstate -
hashchange
これらのイベントがユーザーインタラクションの結果としてディスパッチされる場合、ユーザーエージェントは、 文書の relevant global object について get the next interactionId の手順を実行して取得した一意の interaction id を割り当てなければなりません。あるイベントが、すでに interaction id が割り当てられている以前のインタラクションによってトリガーされた場合、ユーザーエージェントは同じ識別子を再利用するべきです。
click ハンドラーが手動で履歴を操作する場合には、その後の popstate または navigate イベントは独立した
ユーザーインタラクションとはみなされません。
これらのプログラムによってトリガーされたイベントには isTrusted
フラグが設定されていない可能性がありますが、履歴およびナビゲーション API は開始タスクの非同期継続として扱われるため、
[ASYNC-CONTEXT]
を介して元のインタラクションに正しく帰属されます。
navigate、popstate、および hashchange は、ソフトナビゲーションの追跡と
interactionId の割り当てのための内部シグナルとして使用されます。この仕様は、これらのイベント型を
PerformanceEventTiming エントリとしてパフォーマンスタイムラインに公開することを要求せず、
その判断は [EVENT-TIMING]
仕様に委ねます。
processingStart および processingEnd
フックを明示的に定義し、この統合に十分早い段階で interactionId の割り当てが行われるように更新されることが期待されます。現在、
interactionId の割り当ては、通常、イベント処理の終わりまで遅延されます。
unsigned long long を使用しますが、
[EVENT-TIMING]
は現在これを
unsigned long と定義しています。この不一致は、
両仕様の将来のバージョンで解決されることが期待されます。
Window
window について get the next
interactionId するには:
-
window の interaction count を、window の interaction count に 1 を加えた値に設定します。
-
window の initial interactionId value に (window の interaction count × window の interactionId increment)を加えた値を返します。
-
document および event で update interaction contexts for event を呼び出します。
-
interaction id を、event の interaction id とします。
-
document、interaction id、および event で interaction event processing start を呼び出します。
-
interaction context で interaction event timing processing end を呼び出します。
6.3. Largest Contentful Paint (LCP) 統合
この仕様は、paint をインタラクションに帰属させるために [LARGEST-CONTENTFUL-PAINT] アルゴリズムにフックします。
-
contextToNewLargestCandidate を新しい map とします。
-
paintedImages の各 record について:
-
element を、record の pending image record element とします。
-
interaction context を、element の associated interaction context とします。
-
interaction context が null の場合、continue します。
-
size を、element の effective visual size とします。
-
size が null の場合、continue します。
-
interaction context の largest contentful paint が null でなく、かつ size が interaction context の largest contentful paint の
size以下の場合、 continue します。 -
contextToNewLargestCandidate[interaction context] が未設定、または size が contextToNewLargestCandidate[interaction context] の
sizeより大きい場合:-
contextToNewLargestCandidate[interaction context] を element に Set します。
-
-
-
paintedTextNodes の各 textNode について:
-
interaction context を、textNode の associated interaction context とします。
-
interaction context が null の場合、continue します。
-
size を、 textNode の effective visual size とします。
-
size が null の場合、continue します。
-
interaction context の largest contentful paint が null でなく、かつ size が interaction context の largest contentful paint の
size以下の場合、 continue します。 -
contextToNewLargestCandidate[interaction context] が未設定、または size が contextToNewLargestCandidate[interaction context] の
sizeより大きい場合:-
contextToNewLargestCandidate[interaction context] を textNode に Set します。
-
-
-
contextToNewLargestCandidate 内の各 interaction context → newLargestElement について:
-
newLargestElement、document、および interaction context で emit interaction contentful paint entry を呼び出します。
-
document および interaction context で evaluate soft navigation emission を呼び出します。
-
6.4. Container Timing 統合
[CONTAINER-TIMING] API は、共通の DOM 祖先によってレンダリング効果を グループ化する仕組みを提供します。この仕様は、その仕組みと統合して、レンダリングの変更をユーザーインタラクションに 帰属させます。
-
要素の
またはclass style属性が変更された。 -
リソース属性(
imgまたはvideo要素上のsrcなど)が変更された。
次の手順を実行します:
-
interaction context を、get current interaction context を呼び出した結果とします。
-
interaction context が null でない場合:
-
node の associated interaction context を interaction context に設定します。
-
node を([CONTAINER-TIMING] で定義される)コンテナールートとして指定します。
-
node とその各子孫について、([PAINT-TIMING] で定義される)Document の previously reported paints からそれらを削除します。
-
appendChild、innerHTML
更新など)を含む高レベルの説明です。これらを文書構造の変更を追跡する
内部実装フックに対応付けることは、ユーザーエージェントに委ねられます。
さらに、大規模な DOM 変更中に高コストなメインスレッド作業を避けるため、ユーザーエージェントは
子孫を previously reported paints から削除する処理を最適化することが推奨されます。
即時の網羅的な走査の代わりに、ユーザーエージェントは変更されたルートを "dirty" としてマークし、
後続のツリー走査(例: layout または paint 中)でこの状態を遅延伝播できます。
非表示であることが分かっているサブツリー、または content や CSS containment
のような既存の仕組みによって
スキップされるサブツリーも、このリセット処理中にスキップできます。
6.5. Performance Timeline 統合
queue a PerformanceEntry において、ステップ 1(entry の初期化)の後、 次の手順を追加します:
-
newEntry の navigation id が 0 の場合:
-
newEntry の navigation id を global の current navigation id に設定します。
-
7. 重複するインタラクションと競合状態
Web アプリケーションは、多くの場合、複数のユーザーインタラクションを短時間で連続して処理します。この仕様は、 次のモデルを通じてそのような重複するインタラクションを扱います:
-
コンテキストの独立性: 各インタラクションは、それぞれ独自の InteractionContext を独立して管理します。 複数のコンテキストが同時に "in flight" になり、それぞれが独自の URL 変更とコンテンツフルペイントを追跡できます。
-
アクティブ候補の単一性: 多くのインタラクションがアクティブであっても、Document は任意の時点で 1 つの active soft navigation candidate のみを認識します。
-
先取り: インタラクションコンテキストは、最初の同一文書 URL 変更をトリガーした瞬間に active soft navigation candidate になります。後続のインタラクション変更が発生すると、それは前の候補を先取りして新しい候補になります。
-
発行の検証:
SoftNavigationEntryは、発行条件(URL 変更 + コンテンツフルペイント)が満たされた瞬間に active soft navigation candidate であるインタラクションコンテキストに対してのみ発行されます。これにより、ソフトナビゲーションの報告が 文書の現在の視覚状態およびナビゲーション状態と一貫することが保証されます。 -
永続的な帰属: あるインタラクションがソフトナビゲーション候補として先取りされた場合でも、 それがアクティブである限り、自身の
InteractionContentfulPaintエントリを帰属および報告し続けます。これにより、それ自体は「ナビゲーション」と見なされない同時レンダリング更新の 正確な測定が可能になります。