1. はじめに
1.1. 概要
このセクションは規範的ではありません。
ユーザーがウェブサイトを操作する際、自分の行動によって素早くウェブサイトが変化することを期待しています。 実際、調査 によれば、ユーザー入力が100ms以内に処理されない場合は遅いとみなされます。 そのため、ガイドラインに達しなかった入力イベントについて、パフォーマンスタイミング情報を表面化することが重要です。
イベントの待ち時間を監視する一般的な方法は、イベントリスナーを登録することです。
イベントが生成されたタイムスタンプは、イベントのtimeStamp
で取得できます。
加えて、performance.now()
は
イベントハンドラーの処理開始時と終了時の両方で呼び出すことができます。
ハードウェアのタイムスタンプとイベントハンドラーの開始時に取得したタイムスタンプの差分で、
入力遅延(入力が処理され始めるまでの時間)を算出できます。
また、イベントハンドラー開始時と終了時のタイムスタンプの差分で、
イベントハンドラー内で同期的に行われた作業量を算出できます。
最後に、入力が同期的に処理された場合、イベント処理後の次回ペイントまでの期間はユーザー体験の指標として有用です。
この方法にはいくつか根本的な欠陥があります。 第一に、イベントリスナーが必要だと、ページロードの非常に早い段階ではイベント待ち時間の測定ができません。なぜなら、その時点ではリスナーがまだ登録されていない可能性が高いからです。 第二に、入力遅延だけに関心がある開発者も、もともとリスナーがなかったイベントに新たにリスナーを追加せざるを得なくなります。 これはイベント待ち時間の計算に不要なパフォーマンスオーバーヘッドを追加することになります。 さらに、イベントによって発生する非同期処理の計測もこの方法では非常に困難です。
この仕様は、イベント待ち時間の監視の代替手段を提供し、これらの問題の一部を解決します。 ユーザーエージェントがタイムスタンプを算出するため、パフォーマンス測定にイベントリスナーが不要です。 このため、ページロード非常に早期に発生したイベントも計測できます。 また、分析プロバイダがあらゆるイベントをパッチして購読しなくても、遅いイベントを可視化できます。 加えて、不要なイベントリスナーによるウェブサイトのパフォーマンス低下も防げます。 最後に、この仕様により、イベント処理直後のレンダリングタイミングの詳細情報も取得可能となり、 イベントによるウェブサイト変更のオーバーヘッド計測にも役立ちます。
1.2. インタラクション
このセクションは規範的ではありません。
ひとつのユーザーInteraction
(ジェスチャとも呼ばれる)は、通常複数の物理的なハードウェア入力イベントで構成されます。
各物理入力イベントは、ユーザーエージェントによって複数のUIEvent
が発行される原因となり、
それぞれが複数のカスタムイベントリスナーを発火したり、個別のデフォルトアクションをトリガーする場合があります。
例えば、タッチスクリーンデバイスでユーザーが「タップ」操作を行う場合、実際には一連の物理入力イベントから構成されています:
-
タッチ開始、
-
わずかなタッチ移動、
-
タッチ終了。
これらの物理入力イベントは、UIEvent
の一連の発行につながります:
-
...および場合によってはFocusイベントやInputイベントなども間に発行される可能性があります。
これら個々のUIEvent
は、
それぞれが詳細なタイミング測定に役立つ独自のPerformanceEventTiming
エントリ報告対象となります。
注: pointermove
や touchmove
は現時点ではEvent Timingの対象ではありません。
ただし、本仕様では関連するPerformanceEventTiming
を
Interaction
に
interactionId
を使ってグループ化する仕組みも定義しています。
この仕組みはページ応答性指標 Interaction to
Next Paint (INP)の定義にも利用できます。
1.3. 最初の入力
このセクションは規範的ではありません。
最初のユーザーInteraction
は、ユーザー体験に格段に大きな影響を与えることが多く、また非常に遅くなりがちです。
このため、Event Timing APIはWindow
の最初の入力に関するタイミング情報を公開します。
これは、非0のinteractionId
を持つ最初のPerformanceEventTiming
エントリとして定義されます。
通常のPerformanceEventTiming
エントリと異なり、
最初の入力エントリは、指定されたdurationThreshold
を超えなくても報告され、
デフォルトの104msのduration thresholdを超えなくてもバッファリングされます。
この仕組みは、ページ応答性指標 First
Input Delay (FID)の定義に利用できます。
また、イベントハンドラー登録不要でも、常に非常に応答性が高いページも含めてデータ取得できるため、パーセンタイルやパフォーマンス改善の計測にも役立ちます。
1.4. 公開されるイベント
Event Timing APIは特定のイベントのみタイミング情報を公開します。
-
eventの
isTrusted
属性値がfalseの場合、falseを返す。 -
eventの
type
が以下のいずれかの場合:auxclick
、click
、contextmenu
、dblclick
、mousedown
、mouseenter
、mouseleave
、mouseout
、mouseover
、mouseup
、pointerover
、pointerenter
、pointerdown
、pointerup
、pointercancel
、pointerout
、pointerleave
、gotpointercapture
、lostpointercapture
、touchstart
、touchend
、touchcancel
、keydown
、keypress
、keyup
、beforeinput
、input
、compositionstart
、compositionupdate
、compositionend
、dragstart
、dragend
、dragenter
、dragleave
、dragover
、drop
、 trueを返す。 -
falseを返す。
注: mousemove
、
pointermove
、
pointerrawupdate
、
touchmove
、
wheel
、
drag
は「連続的」イベントであるため除外されています。
現在のAPIではこれらイベントのカウントや集計に関する十分なガイダンスがなく、エントリに基づく有意なパフォーマンス指標を得ることが困難なため、これらのイベントタイプは公開されません。
1.5. イベントが測定されるタイミング
このセクションは規範的ではありません。 § 3 処理モデルセクションで公開される情報の概要を説明します。
イベントタイミング情報は特定のイベントのみ公開され、ユーザー入力とその後のペイント操作までの時間差が所定のduration thresholdを超えた場合のみ公開されます。
Event Timing APIは、物理的なユーザー入力発生時点(Event
の
timeStamp
で推定)から、
Event
の
関連グローバルオブジェクトの関連付けられたDocumentのレンダリング更新までの時間を
duration
値として公開します。
この値は8ミリ秒単位で提供されます。
デフォルトでは、Event Timing APIはduration
が104以上の場合のみエントリをバッファリング・公開しますが、開発者はPerformanceObserver
で
別のしきい値を設定可能です。
ただし、これはバッファリングされるエントリには影響せず、bufferedフラグは
デフォルトしきい値以上の過去エントリのみ受け取るために使われます。
Event
の
delayは、ブラウザがイベントハンドラーを実行しようとする時刻とEvent
の
timeStamp
との差分です。
前者はPerformanceEventTiming
の
processingStart
で、
後者はstartTime
で公開されます。
よって、Event
の
delayは
で計算できます。
processingStart
startTime
Event Timing APIはイベントリスナー有無に関わらずエントリを生成します。
特に、最初のクリックや最初のキー入力は、ページ機能に実際にアクセスしようとしたものとは限りません。
ユーザーはテキスト選択や空白領域クリックなどをよく行います。
これは、イベントリスナー登録が遅すぎるページの問題や、イベントリスナーがなくても意味がある入力(ホバー効果等)のパフォーマンスも捉えるための設計方針です。
開発者はprocessingEnd
processingStart
がほぼゼロのエントリを無視することで、
実質的に処理されていない入力を除外できます。
processingEnd
は
イベント発行アルゴリズムが終了した時刻です。
1.6. 使用例
const observer= new PerformanceObserver( function ( list, obs) { for ( let entryof list. getEntries()) { // 入力遅延 const inputDelay= entry. processingStart- entry. startTime; // 処理時間 const processingDuration= entry. processingEnd- entry. processingStart; // 表示遅延 (概算) const presentationDelay= Math. max( 0 , entry. startTime+ entry. duration- entry. processingEnd); // このイベントのtargetに関する情報(例えばid)を取得 const targetId= entry. target? entry. target. id: 'unknown-target' ; console. log( entry. entryType, entry. name, entry. duration, { inputDelay, processingDuration, presentationDelay}); } }); observer. observe({ type: 'first-input' , buffered: true }); observer. observe({ type: 'event' , buffered: true , durationThreshold: 40 });
次の例は、interactionId
ごとのイベント最大durationを辞書として計算します。
この辞書は集計してアナリティクスに報告することができます。
let maxDurations= {}; new PerformanceObserver( list=> { for ( let entryof list. getEntries()) { if ( entry. interactionId> 0 ) { let id= entry. interactionId; if ( ! maxDurations[ id]) { maxDurations[ id] = entry. duration; } else { maxDurations[ id] = Math. max( maxDurations[ id], entry. duration); } } } }). observe({ type: 'event' , buffered: true , durationThreshold: 16 });
このAPIを利用して達成できるユースケース例:
-
ウェブサイトの最初の入力遅延データを収集し、パフォーマンスを継続的に追跡する。
-
ボタンをクリックするとテーブルの並び順が変わる。クリックから並び替え済みコンテンツ表示までの時間を測定。
-
ユーザーがスライダーをドラッグして音量を調整する。スライダーのドラッグ遅延を測定。
-
メニュー項目にホバーするとフライアウトメニューが出る。フライアウト表示までの遅延を測定。
-
最初のユーザークリック(クリックが最初の操作の場合)の遅延の75パーセンタイル値を測定。
2. イベントタイミング
イベントタイミングは以下のインターフェイスを追加します:
2.1.
PerformanceEventTiming
インターフェイス
[Exposed =Window ]interface :
PerformanceEventTiming PerformanceEntry {readonly attribute DOMHighResTimeStamp processingStart ;readonly attribute DOMHighResTimeStamp processingEnd ;readonly attribute boolean cancelable ;readonly attribute Node ?;
target readonly attribute DOMString targetSelector ;readonly attribute unsigned long long interactionId ; [Default ]object (); };
toJSON
PerformanceEventTiming
オブジェクトは、ひとつの対応するEvent
の
タイミング情報を報告します。
各PerformanceEventTiming
オブジェクトには、以下の関連する概念があり、すべて初期値は
です:
-
関連する
Node
を含むeventTarget。
target
属性のgetterは以下の手順を実行します:
-
thisのeventTargetが、nullで paint timing用に公開されていなければ、nullを返す。
-
thisのeventTargetを返す。
注: Event Timing APIを実装するユーザーエージェントは
first
とevent
をsupportedEntryTypes
に含める必要があります(Window
コンテキスト)。
これにより、開発者はイベントタイミングのサポートを検知できます。
このセクションの残りは規範的ではありません。
PerformanceEventTiming
属性値は§ 3 処理モデルで設定されます。
ここではそれらがどのように設定されるかの説明をまとめています。
PerformanceEventTiming
は、PerformanceEntry
インターフェイスの以下の属性を拡張します:
name
name
属性のgetterは、対応するイベントのtype
を返します。entryType
entryType
属性のgetterは「event
」(長いイベントの場合)または「first
」(最初のユーザー操作の場合)を返します。- inputstartTime
startTime
属性のgetterは、対応するイベントのtimeStamp
を返します。duration
duration
属性のgetterは、レンダリング更新が 対応するイベントのDocument
で イベント発行後に完了した時刻とstartTime
の差分(8ms単位で丸め)を返します。
PerformanceEventTiming
には以下の追加属性があります:
processingStart
-
processingStart
属性のgetterは イベント発行アルゴリズムの開始時点のタイムスタンプ(イベントハンドラー実行直前)を返します。 processingEnd
-
processingEnd
属性のgetterは イベント発行アルゴリズムの終了時点のタイムスタンプ(イベントハンドラー実行完了)を返します。イベントハンドラーがなければprocessingStart
と同じです。 cancelable
-
cancelable
属性のgetterは 対応するイベントのcancelable
属性値を返します。 target
-
target
属性のgetterは、対応するイベントの最後のtarget
(そのNode
が切断されておらず、shadow DOMでもない場合)を返します。 targetSelector
-
targetSelector
属性のgetterは、文字列を返す。これは、関連付けられたイベントの最後のtarget
を識別する。 interactionId
-
interactionId
属性のgetterは、 関連付けられたイベントを発生させたユーザーInteraction
を一意に識別する番号を返す。 この属性は、関連付けられたイベントのtype
属性値が以下のいずれかでない限り、0である。-
pointerdown
、pointerup
、click
のいずれかで、タップやドラッグジェスチャに属するもの(ただしpointerdownでスクロールに終わるものは除外)。
-
2.2. EventCounts
インターフェイス
[Exposed =Window ]interface {
EventCounts readonly maplike <DOMString ,unsigned long long >; };
EventCounts
オブジェクトは、キーがイベントタイプ、値がそのtype
で発行されたイベント数の
マップです。
PerformanceEventTiming
エントリでサポートされるtype
(§ 1.4 公開されるイベント参照)のみ、このマップでカウントされます。
2.3. Performance
インターフェイスへの拡張
[Exposed =Window ]partial interface Performance { [SameObject ]readonly attribute EventCounts ;
eventCounts readonly attribute unsigned long long ; };
interactionCount
eventCounts
属性のgetterは、thisの関連グローバルオブジェクトのeventCountsを返します。
interactionCount
属性のgetterは、thisの関連グローバルオブジェクトのinteractionCountを返します。
3. 処理モデル
3.1. DOM仕様への変更
このセクションは[DOM]が変更されたら削除されます。
ステップ1直後に、次のステップを追加します:
-
eventに対し、interactionIdを計算した結果をinteractionIdとする。
-
event、現在の高精度時刻、およびinteractionIdを用いて、イベントタイミングを初期化した結果をtimingEntryとする。
アルゴリズムの戻り値を返す直前に、次のステップを追加します:
-
イベントタイミングの完了処理を、 timingEntry、event、target、現在の高精度時刻を引数として呼び出す。
注: ユーザーエージェントがイベント発行アルゴリズムを省略する場合でも、
そのEvent
について
エントリを追加することが可能です。
この場合、processingStart
の値を推定し、
processingEnd
には同じ値を設定します。
3.2. HTML仕様への変更
このセクションは[HTML]が変更されたら削除されます。
各Window
には以下の関連する概念があります:
-
エントリのキュー待ちリスト:
PerformanceEventTiming
オブジェクトを格納するリスト。初期値は空です。 -
入力イベント発行済フラグ:初期値falseのブール値。
-
ユーザーインタラクション値:初期値は100~10000のランダム整数。
注: ユーザーインタラクション値は0ではなくランダム値に設定されます。これにより、開発者がページ内のインタラクション回数のカウントに依存しないようにする意図があります。 ランダム値で始めることで、開発者がページ内で発生したインタラクション数の信頼できる情報源として利用しにくくなります。
-
保留中のキー押下:整数から
PerformanceEventTimings
へのマップ。初期値は空。 -
ポインターインタラクション値マップ:整数のマップ。初期値は空。
-
保留中のポインター押下:整数から
PerformanceEventTimings
へのマップ。初期値は空。 -
contextmenu発行済フラグ:初期値falseのブール値。
-
eventCounts:type→numEvents形式のマップ。 これは、type属性値が一致するイベントがnumEvents回発行されたことを示します。
Performance
オブジェクトを関連グローバルオブジェクトとして構築する際、 eventCountsは、ユーザーエージェントが§ 1.4 公開されるイベントでサポートするすべてのイベントタイプについて0で初期化されます。 -
interactionCount:固有の
interactionId
が計算された一意なユーザーインタラクション数をカウントする整数。
-
各docs内の完全にアクティブな
Document
について、保留中のイベントタイミングエントリの発行アルゴリズムを呼び出す。
3.3. Performance Timeline仕様への変更
このセクションは[PERFORMANCE-TIMELINE-2]が変更されたら削除されます。
PerformanceObserverInit
辞書が拡張されます:
partial dictionary PerformanceObserverInit {DOMHighResTimeStamp ; };
durationThreshold
3.4. PerformanceEventTiming追加判定
注: 以下のアルゴリズムは[PERFORMANCE-TIMELINE-2]仕様で、
PerformanceEventTiming
エントリをPerformanceObserver
のバッファまたはパフォーマンスタイムラインに追加する必要があるかどうか(レジストリ参照)を決定する際に使用されます。
PerformanceEventTiming
entryとPerformanceObserverInit
optionsを入力として、
PerformanceEventTiming追加判定を行うには、以下の手順を実行します:
-
entryの
entryType
属性値が"first
"の場合、trueを返す。- input -
entryの
entryType
属性値が"event
"であることを確認(assert)する。 -
minDurationを以下のように計算する:
-
optionsが未指定、またはoptionsの
durationThreshold
が未指定の場合、minDurationは104とする。 -
そうでなければ、minDurationは16とoptionsの
durationThreshold
の値の最大値とする。
-
-
entryの
duration
属性値がminDuration以上の場合、trueを返す。 -
そうでなければfalseを返す。
3.5. インタラクション数の増加
Window
型のwindowオブジェクトに対し、インタラクション数の増加を求められた場合、次の手順を実行する:
-
windowのユーザーインタラクション値を、ユーザーエージェントが選択した少量だけ増加させる。
-
interactionCountをwindowのinteractionCountとする。
-
interactionCountをinteractionCount+1に設定する。
注: ユーザーインタラクション値は1ではなくユーザーエージェントが選択した少量だけ増加させる。これにより、開発者がウェブアプリケーションで発生したインタラクション数のカウンターとして誤用しにくくしている。 ユーザーエージェントはポインター押下時に積極的にユーザーインタラクション値を割り当て、例えばpointercancel後に破棄することもできる(遅延計算ではなく即時割り当て)。
ユーザーエージェントは毎回小さなランダム整数で増加させてもよいし、一定値でもよい。
ただしユーザーエージェントは、すべてのWindow
で共有されたグローバルなユーザーインタラクション値を使ってはいけない。これはクロスオリジン情報漏洩の原因となる可能性があるためである。
3.6. interactionIdの算出
-
eventの
isTrusted
属性値がfalseなら0を返す。 -
typeをeventの
type
属性値とする。 -
typeが
keyup
、compositionstart
、input
、pointercancel
、pointerup
、click
、 またはcontextmenu
のいずれでもない場合、0を返す。注:
keydown
やpointerdown
はイベントタイミングの完了処理
でpendingとされ、後からinteractionIdの算出
で後続イベント(keyupやpointerupなど)のために更新される。 -
windowをeventの関連グローバルオブジェクトとする。
-
pendingKeyDownsをwindowの保留中のキー押下とする。
-
pointerMapをwindowのポインターインタラクション値マップとする。
-
pendingPointerDownsをwindowの保留中のポインター押下とする。
-
typeが
keyup
の場合:-
eventの
isComposing
属性値がtrueなら0を返す。 -
codeをeventの
keyCode
属性値とする。 -
pendingKeyDowns[code]が存在しなければ0を返す。
-
entryをpendingKeyDowns[code]とする。
-
windowに対しインタラクション数の増加を行う。
-
interactionIdをwindowのユーザーインタラクション値とする。
-
entryの
interactionId
をinteractionIdに設定する。 -
entryをwindowのエントリのキュー待ちリストに追加する。
-
interactionIdを返す。
-
-
typeが
compositionstart
の場合:-
pendingKeyDownsの値ごとにentryについて:
-
entryをwindowのエントリのキュー待ちリストに追加する。
-
-
0を返す。
-
-
typeが
input
の場合:-
eventが
InputEvent
のインスタンスでなければ0を返す。 注:このチェックにより、typeがinputでもテキスト内容変更と関係ないイベントを除外する。 -
eventの
isComposing
属性値がfalseなら0を返す。 -
windowに対しインタラクション数の増加を行う。
-
windowのユーザーインタラクション値を返す。
-
-
それ以外の場合(typeが
pointercancel
、pointerup
、click
、 またはcontextmenu
の場合):-
pointerIdをeventの
pointerId
属性値とする。 -
typeが
click
の場合:-
pointerMap[pointerId]が存在しなければ0を返す。
-
valueをpointerMap[pointerId]とする。
-
pointerMap[pointerId]を削除する。
-
valueを返す。
-
-
typeが
pointerup
、pointercancel
、 またはcontextmenu
であることを確認する。 -
pendingPointerDowns[pointerId]が存在しない場合:
-
typeが
contextmenu
の場合、windowのユーザーインタラクション値を返す。 -
typeが
pointerup
でwindowのcontextmenu発行済フラグがtrueの場合:-
windowのcontextmenu発行済フラグをfalseに設定する。
-
windowのユーザーインタラクション値を返す。
-
-
それ以外は0を返す。
-
-
pointerDownEntryをpendingPointerDowns[pointerId]とする。
-
pointerDownEntryが
PerformanceEventTiming
エントリであることを確認する。 -
typeが
pointerup
またはcontextmenu
の場合:-
windowに対しインタラクション数の増加を行う。
-
pointerMap[pointerId]をwindowのユーザーインタラクション値に設定する。
-
pointerDownEntryの
interactionId
をpointerMap[pointerId]に設定する。
-
-
pointerDownEntryをwindowのエントリのキュー待ちリストに追加する。
-
pendingPointerDowns[pointerId]を削除する。
-
typeが
contextmenu
の場合、windowのcontextmenu発行済フラグをtrueに設定する。 -
typeが
pointercancel
の場合、0を返す。 -
pointerMap[pointerId]を返す。
-
注: このアルゴリズムはイベントを対応するインタラクションIDに割り当てようとする。
キーボードイベントでは、keydown
で新しいインタラクションIDが発生し、keyup
は前のkeydown
とID一致させる必要がある。
ポインターイベントでは、pointerdown
ではpointercancel
やpointerup
発生までIDが確定しない。
click
は直前のpointerdown
のIDと一致させる。
pointercancel
やpointerup
が起きれば、pointerdown
に対応するエントリのIDを設定できる。
pointercancel
なら、pointerdown
に新しいIDは割り当てない。
pointerup
なら新IDを計算し、pointerdown
とpointerup
両方に設定する(その後clickにも設定可能)。
3.7. イベントタイミングの初期化
-
アルゴリズム「eventがEvent Timingの対象かどうか」を実行してfalseなら、nullを返す。
-
timingEntryをeventの関連realmで新しい
PerformanceEventTiming
オブジェクトとして生成。 -
timingEntryの
entryType
に"event
"を設定。 -
timingEntryの
processingStart
にprocessingStartを設定。 -
timingEntryの
cancelable
にeventのcancelable
属性値を設定。 -
timingEntryの
interactionId
にinteractionIdを設定。 -
timingEntryを返す。
3.8. イベントタイミングの完了
-
もし timingEntry が null なら、return する。
-
relevantGlobal を target の 関連するグローバルオブジェクトとする。
-
もし relevantGlobal が implements
Window
でないなら、return する。 -
timingEntry の
processingEnd
に processingEnd を設定する。 -
Assert: target が implements
Node
である。注: このアサーションは Event Timing API がサポートするイベント型によって保証される。
-
timingEntry の関連付けられた eventTarget に target を設定する。
注: これにより eventTarget は最後のイベントターゲットになる。retargeting が発生した場合、root に最も近い最後のターゲットが使われる。
-
timingEntry の
targetSelector
に、target を入力として CSSセレクター生成アルゴリズムを実行した結果を設定する。 -
もし event の
type
属性値がpointerdown
である場合:-
pendingPointerDowns を relevantGlobal の 保留中pointerdownとする。
-
pointerId を event の
pointerId
とする。 -
もし pendingPointerDowns[pointerId] が存在するなら:
-
previousPointerDownEntry を pendingPointerDowns[pointerId] とする。
-
previousPointerDownEntry を relevantGlobal の キューされるエントリに追加する。
-
-
pendingPointerDowns[pointerId] に timingEntry を設定する。
-
window の is contextmenu triggered を false に設定する。
-
-
それ以外で、event の
type
属性値がkeydown
である場合:-
もし event の
isComposing
属性値が
なら:true -
timingEntry を relevantGlobal の キューされるエントリに追加する。
-
return する。
-
-
pendingKeyDowns を relevantGlobal の 保留中keydownとする。
-
code を event の
keyCode
属性値とする。 -
もし pendingKeyDowns[code] が存在するなら:
-
previousKeyDownEntry を pendingKeyDowns[code] とする。
-
code が 229 でない場合:
-
window の ユーザー操作値 をユーザーエージェントが選択した小さな値だけ増加させる。
-
previousKeyDownEntry の
interactionId
を window の ユーザー操作値 に設定する。
注: 229はIMEキーボードイベントに該当する特別なケース。ユーザーエージェントから複数回送信される場合があり、キーの長押しとは対応しない場合もある。
-
-
previousKeyDownEntry を window の キューされるエントリに追加する。
-
-
pendingKeyDowns[code] に timingEntry を設定する。
-
-
それ以外の場合:
-
timingEntry を relevantGlobal の キューされるエントリに追加する。
-
3.9. 保留中のイベントタイミングエントリの発行
Document
型のdocについて求められた場合、以下の手順を実行する:
-
windowをdocの関連グローバルオブジェクトとする。
-
renderingTimestampを現在の高精度時刻とする。
-
windowのエントリのキュー待ちリスト内の各timingEntryについて:
-
イベントタイミングエントリのduration設定を、timingEntry、window、renderingTimestampを入力として実行。
-
timingEntryの
duration
属性値が16以上なら、timingEntryをキューする。
-
-
windowのエントリのキュー待ちリストをクリアする。
-
windowの保留中のポインター押下の値ごとにpendingPointerDownEntryについて:
-
イベントタイミングエントリのduration設定を、pendingPointerDownEntry、window、renderingTimestampを入力として実行。
-
-
windowの保留中のキー押下の値ごとにpendingKeyDownEntryについて:
-
イベントタイミングエントリのduration設定を、pendingKeyDownEntry、window、renderingTimestampを入力として実行。
-
PerformanceEventTiming
型のtimingEntry、Window
型のwindow、DOMHighResTimeStamp
型のrenderingTimestampを入力として求められた場合、以下の手順を実行する:
-
timingEntryの
duration
属性値が0以外ならreturn。 -
startをtimingEntryの
startTime
属性値とする。 -
timingEntryの
duration
に、DOMHighResTimeStamp
としてrenderingTimestamp
(8ms以下の粒度)を設定。- start -
nameをtimingEntryの
name
属性値とする。 -
以下の手順でイベント数を更新:
-
eventCountsをwindowのeventCountsとする。
-
eventCountsがnameを含むことを確認。
-
-
windowの入力イベント発行済フラグがfalseで、timingEntryの
interactionId
が0でなければ、以下の手順を実行:-
firstInputEntryをtimingEntryのコピーとする。
-
firstInputEntryの
entryType
に"first
"を設定。- input -
windowの入力イベント発行済フラグをtrueに設定。
-
3.10. ターゲットセレクター
EventTarget
target を受け取り、以下の手順を実行する:
-
もし target が
Node
であれば、次の手順を実行する: -
それ以外の場合、空文字列を返す。
4. セキュリティおよびプライバシーに関する考慮事項
高精度タイマーをウェブプラットフォームに追加することは、セキュリティ上の懸念があるため望ましくありません。
イベントハンドラーのタイムスタンプは、performance.now()
と同じ精度です。
processingStart
やprocessingEnd
はこのAPIを使わなくても算出可能なので、
これら属性を公開することが新たな攻撃面を生むことはありません。
よって、duration
のみが追加の考慮を要します。
duration
は8ミリ秒の粒度(丸め処理による)で提供されます。
そのため、高精度タイマーをこのタイムスタンプから生成することはできません。
ただし、イベント処理後のピクセル描画時間という、ウェブ開発者が容易に取得できない新たな情報が公開されます。
このタイムスタンプの公開は粒度を考慮すれば、セキュリティやプライバシー上の懸念はないと考えています。
有用な新情報を最小限だけ公開する目的で、粒度は8ミリ秒としました。
これにより、120Hzディスプレイでも十分に正確なタイミング計測が可能です。
duration
のデフォルト閾値104msは、100msを超える最初の8の倍数です。
丸め前のdurationが100ms以上であれば、丸め結果も104ms以上となります。
このようなイベントは100ms以内に処理されず、ユーザー体験に悪影響を及ぼす可能性があります。
durationThreshold
の最小値16msは、
応答が滑らかであることを保証する一般的なユースケースのためです。120Hzディスプレイでは、1フレーム以上スキップする応答は16ms以上となり、
この値以上のユーザー入力はAPIで取得できます。