1. はじめに
1.1. 概要
このセクションは規範的ではありません。
ユーザーがウェブサイトを操作する際、自分の行動によって素早くウェブサイトが変化することを期待しています。 実際、調査 によれば、ユーザー入力が100ms以内に処理されない場合は遅いとみなされます。 そのため、ガイドラインに達しなかった入力イベントについて、パフォーマンスタイミング情報を表面化することが重要です。
イベントの待ち時間を監視する一般的な方法は、イベントリスナーを登録することです。
イベントが生成されたタイムスタンプは、イベントのtimeStampで取得できます。
加えて、performance.now()は
イベントハンドラーの処理開始時と終了時の両方で呼び出すことができます。
ハードウェアのタイムスタンプとイベントハンドラーの開始時に取得したタイムスタンプの差分で、
入力遅延(入力が処理され始めるまでの時間)を算出できます。
また、イベントハンドラー開始時と終了時のタイムスタンプの差分で、
イベントハンドラー内で同期的に行われた作業量を算出できます。
最後に、入力が同期的に処理された場合、イベント処理後の次回ペイントまでの期間はユーザー体験の指標として有用です。
この手法には根本的な欠陥がいくつかあります。 第一に、イベントリスナーの必須化によって、ページ読み込みの非常に早い段階でイベント遅延を計測することができなくなります——なぜなら、その時点でリスナーがまだ登録されていない場合があるからです。 第二に、入力遅延にだけ関心がある開発者であっても、元々リスナーがなかったイベントに新たにリスナーを追加せざるを得なくなります。 これによって、イベント遅延の計算に不要なパフォーマンス負荷がかかることになります。 さらに最後に、この手法ではイベントによって引き起こされた非同期処理の計測は非常に難しくなります。
この仕様は、イベント待ち時間の監視の代替手段を提供し、これらの問題の一部を解決します。 ユーザーエージェントがタイムスタンプを算出するため、パフォーマンス測定にイベントリスナーが不要です。 このため、ページロード非常に早期に発生したイベントも計測できます。 また、分析プロバイダがあらゆるイベントをパッチして購読しなくても、遅いイベントを可視化できます。 加えて、不要なイベントリスナーによるウェブサイトのパフォーマンス低下も防げます。 最後に、この仕様により、イベント処理直後のレンダリングタイミングの詳細情報も取得可能となり、 イベントによるウェブサイト変更のオーバーヘッド計測にも役立ちます。
1.2. インタラクション
この節は規範的ではありません。
単一のユーザーによる Interaction
(ジェスチャーと呼ばれることもあります)は、通常、複数の物理的なハードウェア入力イベントで構成されます。
各物理入力イベントによって、ユーザーエージェントが複数の UIEvent
をディスパッチする場合があり、
それぞれが複数のカスタムイベントリスナーを呼び出したり、異なる既定のアクションを引き起こしたりする場合があります。
例えば、タッチスクリーンデバイスでの単一のユーザーによる「タップ」インタラクションは、実際には一連 の物理入力イベントで構成されます。
-
タッチの開始、
-
ごくわずかなタッチの移動、
-
タッチの終了。
これらの物理入力イベントは、一連の UIEvent
をディスパッチする場合があります。
-
…さらに、その間にフォーカスイベントや入力イベントなどが発生する可能性もあります。
これら個々の UIEvent
は、
それぞれ独自の PerformanceEventTiming
エントリーとして報告される候補となり、詳細なタイミングの把握に役立ちます。
注記: pointermove
および touchmove
は現在、Event Timing の対象として考慮されていません。
ただし、この仕様では、関連する PerformanceEventTiming
を
一つの Interaction
に
まとめるための interactionId
を使った仕組みも定義しています。
この仕組みは、ページの応答性の指標である 次の描画までの
インタラクション(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で、
後者はPerformanceEventTimingの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
インターフェイスの以下の属性を拡張します:
namename属性のgetterは、対応するイベントのtypeを返します。entryTypeentryType属性のgetterは「event」(長いイベントの場合)または「first」(最初のユーザー操作の場合)を返します。- inputstartTimestartTime属性のgetterは、対応するイベントのtimeStampを返します。durationduration属性の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
、値がその type
の
発火したイベント数となるマップである。
このマップでカウントされるのは、 type
が
PerformanceEventTiming
エントリ(§ 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属性値が type に等しいイベントが numEvents 個発火されたことを意味する。Performanceオブジェクトが、その 関連グローバルオブジェクト がWindowである場合に構築されたとき、 その eventCounts は § 1.4 公開されるイベント に記載されたリストのうち、 ユーザーエージェントがサポートする全イベントタイプについて 0 を含むマップに初期化されなければならない。 -
interactionCount:固有の
interactionIdが計算された一意なユーザーインタラクション数をカウントする整数。
-
各docs内の完全にアクティブな
Documentについて、その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は イベントタイミングの確定時に保留としてマークされ、その後、 将来のイベント(例えばkeyupやpointerup)について interactionId を計算する際に更新されます。 -
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 の キューに追加される エントリーに追加します。
-
pendingKeyDowns[code] を 削除します。
-
interactionId を返します。
-
-
type が
compositionstartの場合:-
pendingKeyDowns の 値に含まれる各 entry について:
-
entry を window の キューに追加される エントリーに追加します。
-
-
pendingKeyDowns を クリアします。
-
0 を返します。
-
-
type が
inputの場合:-
event が
InputEventのインスタンスでない場合、 0 を返します。 注記:この検査は、Eventsのうち、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
はその ID を以前の keydown
の ID と一致させる必要があります。
ポインターイベントの場合、pointerdown
を受け取ったとき、
その pointercancel
または pointerup
が発生するまで待ってから、その interactionId
を知る必要があります。
また、click
を以前の pointerdown
のインタラクション ID と一致させようとします。
pointercancel
または pointerup
が発生すると、保存されている interactionId
を
pointerdown
に対応するエントリーに設定できるようになります。
それが 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 を設定する。
-
relevantGlobal の 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 でない場合:
-
relevantGlobal の ユーザー操作値 をユーザーエージェントが選択した小さな値だけ増加させる。
-
previousKeyDownEntry の
interactionIdを relevantGlobal の ユーザー操作値 に設定する。
注: 229はIMEキーボードイベントに該当する特別なケース。ユーザーエージェントから複数回送信される場合があり、キーの長押しとは対応しない場合もある。
-
-
previousKeyDownEntry を relevantGlobal の キューされるエントリに追加する。
-
-
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で取得できます。