Long Animation Frames API(LoAF)は、ユーザー インターフェース(UI)の更新の遅延をより正確に把握できるように Long Tasks API を更新したものです。これは、応答性を測定する Core Web Vitals 指標である Interaction to Next Paint(INP)に影響する可能性のあるアニメーション フレームの遅延を特定したり、スムーズさに影響する他の UI ジャンクを特定したりするのに役立ちます。
API のステータス
Chrome 116 ~ Chrome 122 のオリジン トライアルに続いて、LoAF API は Chrome 123 からリリースされました。
背景: Long Tasks API
Long Animation Frames API は、Chrome で長い間(Chrome 58 以降)利用可能な Long Tasks API の代替手段です。名前が示すように、Long Task API を使用すると、長時間のタスク(メインスレッドを 50 ミリ秒以上占有するタスク)をモニタリングできます。長時間のタスクは、PeformanceObserver
を使用して PerformanceLongTaskTiming
インターフェースでモニタリングできます。
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: 'longtask', buffered: true });
タスクが長すぎると、応答性に問題が生じる可能性があります。ユーザーがページの操作(ボタンのクリックやメニューの開くなど)を試みても、メインスレッドがすでに長いタスクを処理している場合、そのタスクが完了するまでユーザーの操作が遅延します。
応答性を高めるには、長いタスクを分割することをおすすめします。長いタスクを複数の小さなタスクに分割すると、インタラクションへの応答に大幅な遅延が生じるのを回避するために、それらのタスクの間により重要なタスクを実行できる場合があります。
そのため、応答性を改善しようとする際、多くの場合、最初の作業はパフォーマンス トレースを実行して長時間のタスクを確認することです。たとえば、Lighthouse などのラボベースの監査ツール(長いメインスレッド タスクを回避する監査があります)を使用するか、Chrome DevTools で長いタスクを確認します。
ラボベースのテストは、レスポンシビリティの問題を特定する際には適切でないことが多いため、これらのツールにインタラクションが含まれていない場合があります。含まれている場合でも、想定されるインタラクションのサブセットにすぎません。理想的には、フィールドでインタラクションの遅延の原因を測定します。
Long Tasks API の欠点
フィールドで長いタスクを Performance Observer を使用して測定することは、ある程度役立ちます。実際には、長いタスクが発生したという事実と、その時間以外にあまり多くの情報は得られません。
リアルユーザー モニタリング(RUM)ツールでは、この情報を使用して長時間のタスクの数や所要時間の傾向を把握したり、長時間のタスクが発生したページを特定したりすることがよくあります。ただし、長時間のタスクの原因に関する詳細情報がないと、この情報の用途は限られます。Long Tasks API には基本的なアトリビューション モデルのみが用意されています。このモデルでは、長時間タスクが発生したコンテナ(最上位ドキュメントまたは <iframe>
)のみが判明し、呼び出したスクリプトや関数は判明しません。これは、次の典型的なエントリで示されています。
{
"name": "unknown",
"entryType": "longtask",
"startTime": 31.799999997019768,
"duration": 136,
"attribution": [
{
"name": "unknown",
"entryType": "taskattribution",
"startTime": 0,
"duration": 0,
"containerType": "window",
"containerSrc": "",
"containerId": "",
"containerName": ""
}
]
}
Long Tasks API も不完全なビューです。一部の重要なタスクが除外される場合があるためです。レンダリングなどの更新は、別々のタスクで行われますが、理想的には、その更新を引き起こした前の実行とともに、そのインタラクションの「合計作業量」を正確に測定するために、そのタスクを含める必要があります。タスクに依存する制限事項の詳細については、説明の「長いタスクの限界」セクションをご覧ください。
最後の問題は、長いタスクの測定では、50 ミリ秒の制限を超える個々のタスクのみがレポートされることです。アニメーション フレームは、この 50 ミリ秒の制限よりも小さい複数のタスクで構成されている場合がありますが、それでもブラウザのレンダリング能力をブロックする可能性があります。
Long Animation Frames API
Long Animation Frames API(LoAF)は、Long Tasks API の欠点の一部に対処することを目的とした新しい API です。これにより、デベロッパーは、応答性の問題に対処し、INP を改善するために、より実用的な分析情報を入手できるようになります。また、スムーズさに関する問題に関する分析情報も入手できます。
応答性が良好とは、ページが操作に対して迅速に応答することを意味します。つまり、ユーザーが必要とする更新をタイムリーにペイントし、これらの更新がブロックされないようにする必要があります。INP の場合は200 ミリ秒以内に応答することをおすすめしますが、他の更新(アニメーションなど)の場合は 200 ミリ秒でも長すぎる場合があります。
Long Animation Frames API は、ブロック作業を測定する代替手段です。Long Animation Frames API は、その名のとおり、個々のタスクではなく長いアニメーション フレームを測定します。長いアニメーション フレームとは、レンダリングの更新が 50 ミリ秒を超えて遅延した場合です(Long Tasks API のしきい値と同じ)。
長いアニメーション フレームは、レンダリングを必要とするタスクの開始から測定されます。長いアニメーション フレームの最初のタスクでレンダリングが不要な場合、レンダリング以外のタスクの完了時に長いアニメーション フレームが終了し、次のタスクで新しい長いアニメーション フレームが開始されます。このようなレンダリングされない長いアニメーション フレームは、50 ミリ秒を超える場合(renderStart
時間が 0 の場合)は、ブロックする可能性のある作業を測定できるように、Long Animation Frames API に引き続き含まれます。
長いアニメーション フレームは、PerformanceObserver
を使用した長いタスクと同様に確認できますが、代わりに long-animation-frame
タイプを確認します。
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: 'long-animation-frame', buffered: true });
以前の長いアニメーション フレームは、パフォーマンス タイムラインから次のようにクエリすることもできます。
const loafs = performance.getEntriesByType('long-animation-frame');
ただし、パフォーマンス エントリの maxBufferSize
があり、それ以降のエントリは破棄されるため、PerformanceObserver アプローチをおすすめします。long-animation-frame
バッファサイズは、long-tasks
と同じ 200 に設定されています。
タスクではなくフレームを確認するメリット
タスクの観点ではなくフレームの観点からこれを検討する主な利点は、長いアニメーションを任意の数のタスクで構成し、累積的に長いアニメーション フレームを作成できることです。これは、前述の最後のポイントに対応しています。アニメーション フレームの前に、レンダリングをブロックする小さなタスクが多数あり、その合計が Long Tasks API によってサーフェス表示されなくなる可能性があります。
長いタスクのこの代替ビューのもう 1 つの利点は、フレーム全体のタイミングの内訳を把握できることです。Long Tasks API のように startTime
と duration
のみを指定せず、LoAF ではフレーム時間のさまざまな部分をより詳細に分類します。
フレームのタイムスタンプと時間
startTime
: ナビゲーションの開始時間を基準とした長いアニメーション フレームの開始時間。duration
: 長いアニメーション フレームの時間(表示時間は含まない)。renderStart
: レンダリング サイクルの開始時間(requestAnimationFrame
コールバック、スタイルとレイアウトの計算、サイズ変更オブザーバー、インターセクション オブザーバーのコールバックを含む)。styleAndLayoutStart
: スタイルとレイアウトの計算に費やされた期間の開始時間。firstUIEventTimestamp
: このフレーム中に処理される最初の UI イベント(マウス/キーボードなど)の時間。イベントの発生と処理の間に遅延があった場合、firstUIEventTimestamp
は前のフレームにある可能性があります。blockingDuration
: アニメーション フレームが入力やその他の優先度の高いタスクの処理をブロックする合計時間(ミリ秒単位)。
blockingDuration
の説明
長いアニメーション フレームは、複数のタスクで構成されている場合があります。blockingDuration
は、50 ミリ秒を超えるタスクの実行時間の合計(最長のタスク内の最終的なレンダリング時間を含む)です。
たとえば、長いアニメーション フレームが 55 ミリ秒と 65 ミリ秒の 2 つのタスクで構成され、その後に 20 ミリ秒のレンダリングが続く場合、duration
は約 140 ミリ秒で、blockingDuration
は(55 - 50)+(65 + 20 - 50)= 40 ミリ秒になります。この 140 ミリ秒のアニメーション フレームのうち 40 ミリ秒は、入力の処理がブロックされたフレームと見なされます。
duration
と blockingDuration
のどちらを確認するか
一般的な 60 Hz ディスプレイの場合、ブラウザは(スムーズな更新を確保するために)少なくとも 16.66 ミリ秒ごとに、または(レスポンシブな更新を確保するために)入力処理などの優先度の高いタスクの後に、フレームのスケジュールを設定しようとします。ただし、入力も他の優先度の高いタスクもないが、他のタスクのキューがある場合、通常、ブラウザは、タスクがどれだけ細かく分割されているかにかかわらず、現在のフレームを 16.66 ミリ秒をはるかに超えて継続します。つまり、ブラウザは常に入力を優先しようとしますが、レンダリングの更新よりもタスクのキューに対応することを選択する場合があります。これは、レンダリングが負荷の高いプロセスであるため、複数のタスクの組み合わせによるレンダリング タスクを処理すると、通常は全体的な作業量が削減されるためです。
したがって、blockingDuration
が低いまたはゼロの長いアニメーション フレームでも、入力に応答しているように感じられる必要があります。したがって、長いタスクを分割して blockingDuration
を減らすか、完全になくすことが、INP で測定される応答性の向上に重要です。
ただし、blockingDuration
に関係なく、長いアニメーション フレームが多数ある場合は、UI の更新が遅れていることを示します。そのため、INP で測定される応答性の問題は少ないものの、スムーズさに影響し、スクロールやアニメーションのユーザー インターフェースが遅いと感じられる可能性があります。この領域の問題を把握するには、duration
を確認します。ただし、作業を分割して解決することはできず、作業を減らす必要があるため、最適化が難しい場合があります。
フレームタイミング
前述のタイムスタンプを使用すると、長いアニメーション フレームを次のようにタイミングに分割できます。
タイミング | 計算 |
---|---|
開始時刻 | startTime |
終了時刻 | startTime + duration |
勤務時間 | renderStart ? renderStart - startTime : duration |
レンダリング所要時間 | renderStart ? (startTime + duration) - renderStart: 0 |
レンダリング: レイアウト前の時間 | styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0 |
レンダリング: スタイルとレイアウトの時間 | styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0 |
スクリプト アトリビューションの改善
long-animation-frame
エントリタイプには、長いアニメーション フレームに貢献した各スクリプトのアトリビューション データが含まれています(5 ミリ秒を超えるスクリプトの場合)。
Long Tasks API と同様に、アトリビューション エントリの配列で提供されます。各エントリには次の詳細が含まれます。
name
とEntryType
の両方がscript
を返します。- スクリプトの呼び出し方法を示す意味のある
invoker
('IMG#id.onload'
、'Window.requestAnimationFrame'
、'Response.json.then'
など)。 - スクリプト エントリ ポイントの
invokerType
:user-callback
: ウェブ プラットフォーム API から登録された既知のコールバック(setTimeout
、requestAnimationFrame
など)。event-listener
: プラットフォーム イベントのリスナー(click
、load
、keyup
など)。resolve-promise
: プラットフォームの Promise のハンドラ(例:fetch()
)。なお、Promise の場合、同じ Promise のハンドラはすべて 1 つの「スクリプト」として混在します。.
reject-promise
:resolve-promise
と同じですが、不承認の場合。classic-script
: スクリプトの評価(例:<script>
、import()
)module-script
:classic-script
と同じですが、モジュール スクリプト用です。
- そのスクリプトの個別のタイミング データ:
startTime
: エントリ関数が呼び出された時刻。duration
:startTime
から、後続のマイクロタスク キューの処理が完了するまでの時間。executionStart
: コンパイル後の時間。forcedStyleAndLayoutDuration
: この関数内で強制レイアウトとスタイルの処理に費やされた合計時間(スラッシングを参照)。pauseDuration
: 同期オペレーションの「一時停止」に費やされた合計時間(アラート、同期 XHR)。
- スクリプト ソースの詳細:
sourceURL
: 利用可能な場合のスクリプト リソース名(見つからない場合は空)。sourceFunctionName
: 使用可能なスクリプト関数名(見つからない場合は空)。sourceCharPosition
: 使用可能なスクリプト文字の位置(見つからない場合は -1)。
windowAttribution
: 長いアニメーション フレームが発生したコンテナ(最上位ドキュメントまたは<iframe>
)。window
: 同じオリジンのウィンドウへの参照。
ソースエントリが指定されている場合、デベロッパーは長いアニメーション フレーム内の各スクリプトがどのように呼び出されたか、呼び出し元のスクリプトの文字位置まで正確に把握できます。これにより、長いアニメーション フレームの原因となった JavaScript リソース内の正確な場所が示されます。
long-animation-frame
パフォーマンス エントリの例
単一のスクリプトを含む long-animation-frame
パフォーマンス エントリの例を以下に示します。
{
"blockingDuration": 0,
"duration": 60,
"entryType": "long-animation-frame",
"firstUIEventTimestamp": 11801.099999999627,
"name": "long-animation-frame",
"renderStart": 11858.800000000745,
"scripts": [
{
"duration": 45,
"entryType": "script",
"executionStart": 11803.199999999255,
"forcedStyleAndLayoutDuration": 0,
"invoker": "DOMWindow.onclick",
"invokerType": "event-listener",
"name": "script",
"pauseDuration": 0,
"sourceURL": "https://web.dev/js/index-ffde4443.js",
"sourceFunctionName": "myClickHandler",
"sourceCharPosition": 17796,
"startTime": 11803.199999999255,
"window": [Window object],
"windowAttribution": "self"
}
],
"startTime": 11802.400000000373,
"styleAndLayoutStart": 11858.800000000745
}
このように、ウェブサイトはこれまで以上に多くのデータを取得して、レンダリング アップデートの遅延の原因を把握できるようになります。
フィールドで Long Animation Frames API を使用する
Chrome DevTools や Lighthouse などのツールは、問題の検出と再現に役立ちますが、ラボツールであるため、フィールド データでしか得られないユーザー エクスペリエンスの重要な側面を見落とす可能性があります。
Long Animation Frames API は、Long Tasks API では収集できない、ユーザー操作に関する重要なコンテキスト データをフィールドで収集するように設計されています。これにより、他の方法では発見できなかったインタラクティビティに関する問題を特定して再現できます。
長いアニメーション フレーム API のサポート機能の検出
次のコードを使用して、API がサポートされているかどうかをテストできます。
if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
// Monitor LoAFs
}
最長の INP インタラクションへのリンク
Long Animation Frames API の最も明らかなユースケースは、次のペイントへのインタラクション(INP)の問題の診断と修正に役立つことです。これは、Chrome チームがこの API を開発した主な理由の一つでした。良好な INP とは、インタラクションからフレームがペイントされるまでのすべてのインタラクションに 200 ミリ秒以内に応答する INP です。Long Animation Frames API は 50 ミリ秒以上の時間を要するすべてのフレームを測定するため、問題のある INP のほとんどには、インタラクションを診断するために LoAF データを含める必要があります。
「INP LoAF」は、次の図に示すように、INP インタラクションを含む LoAF です。
場合によっては、INP イベントが 2 つの LoAF にまたがることがあります。通常は、フレームが前回のフレームのレンダリング部分を開始した後にインタラクションが発生し、イベント ハンドラが次のフレームで処理される場合に発生します。
まれに、2 つを超える LoAF にまたがることもあります。
INP インタラクションに関連付けられた LoAF データを記録すると、INP インタラクションに関する詳細な情報を取得して診断に役立てることができます。これは、入力遅延を把握する際に特に役立ちます。そのフレームで実行されていた他のスクリプトを確認できます。
また、イベント ハンドラでこれらの値が再現されない場合は、説明できない処理時間と表示遅延を把握することも役に立ちます。ユーザーに対して、ご自身のテストに含まれていない他のスクリプトが実行されている可能性があります。
INP エントリを関連する LoAF エントリにリンクする直接の API はありませんが、各エントリの開始時間と終了時間を比較することで、コードでリンクすることは可能です(WhyNp サンプル スクリプトをご覧ください)。web-vitals
ライブラリには、v4 の INP アトリビューション インターフェースの longAnimationFramesEntries
プロパティに含まれる、重複するすべての LoAF が含まれています。
LoAF エントリをリンクしたら、INP アトリビューションを含む情報を含めることができます。scripts
オブジェクトには、そのフレームで実行されていた他の処理も示されるため、非常に有用な情報が含まれています。このデータをアナリティクス サービスにビーコンで送信すると、インタラクションの遅延の原因を詳しく把握できます。
INP インタラクションの LoAF を報告すると、ページで最も緊急性の高いインタラクションの問題を特定できます。ユーザーによってページの操作は異なるため、十分な量の INP アトリビューション データが収集されると、INP アトリビューション データにさまざまな問題が含まれる可能性があります。これにより、スクリプトをボリューム別に並べ替えて、INP の遅延と関連するスクリプトを確認できます。
長いアニメーションのデータをアナリティクス エンドポイントに報告する
INP LoAF のみを確認するデメリットの一つは、将来の INP の問題の原因となる可能性のある改善の余地を見逃す可能性があることです。そのため、INP の問題を修正して大幅な改善を期待しても、次に遅いインタラクションの時間がわずかに短縮されただけで、INP の改善があまり進まない、という状況に陥る可能性があります。
そのため、INP LoAF のみを見るのではなく、ページのライフタイム全体のすべての LoAF を検討することをおすすめします。
ただし、各 LoAF エントリには大量のデータが含まれているため、分析対象を一部のロアフのみに制限することをおすすめします。また、長いアニメーション フレームのエントリは非常に大きい場合があるため、エントリから分析に送信するデータをデベロッパーが決定する必要があります。たとえば、エントリの概要時間やスクリプト名、または必要と判断されるその他のコンテキスト データの最小セットなどです。
長いアニメーション フレーム データの量を減らすための推奨されるパターンには、次のようなものがあります。
- インタラクションのある長いアニメーション フレームを観察する
- ブロック時間が長い長いアニメーション フレームを観察する
- 重要な UI の更新中に長いアニメーション フレームを検出してスムーズさを改善
- 長いアニメーションのフレームで最悪のパフォーマンスを確認する
- 長いアニメーション フレームの一般的なパターンを特定する
どのパターンが最適かは、最適化の進捗状況と、長いアニメーション フレームの頻度によって異なります。レスポンシブ デザインを最適化したことがないサイトでは、LoAF が多数存在する可能性があります。そのような場合は、インタラクションが発生した LoAF のみに絞り込むか、高いしきい値を設定する、または最も問題のある LoAF のみを確認することをおすすめします。
一般的な応答性の問題を解決したら、インタラクションや長時間のブロックのみに制限せず、しきい値を下げて範囲を広げることができます。
インタラクションのある長いアニメーション フレームをモニタリングする
INP の長いアニメーション フレーム以外の分析情報を得るには、blockingDuration
が高いインタラクション(firstUIEventTimestamp
値の有無で検出可能)を含むすべての LoAF を確認します。
また、2 つの関連付けを試みるよりも、INP LoAF をモニタリングする簡単な方法でもあります。ほとんどの場合、特定のアクセスの INP LoAF が含まれますが、含まれない場合でも、他のユーザーの INP インタラクションである可能性があるため、修正が必要な長いインタラクションが表示されます。
次のコードは、フレーム中にインタラクションが発生したすべての LoAF エントリを、blockingDuration
が 100 ミリ秒を超える場合にロギングします。ここで 100 が選択されているのは、200 ミリ秒の「良好な」INP しきい値よりも小さいためです。必要に応じて、値を大きくしたり小さくしたりできます。
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
entry.firstUIEventTimestamp > 0
) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
長いアニメーション フレームと長いブロック時間を確認する
インタラクションのある長いアニメーション フレームすべてを確認する代わりに、ブロック時間が長い長いアニメーション フレームすべてを確認することをおすすめします。これらの長いアニメーション フレーム中にユーザーが操作した場合、潜在的な INP の問題が発生する可能性があります。
次のコードは、フレーム中にインタラクションが発生した、ブロック時間が 100 ミリ秒を超えるすべての LoAF エントリをロギングします。ここで 100 が選択されているのは、200 ミリ秒の「良好」な INP しきい値よりも小さいため、潜在的な問題のフレームを特定しつつ、報告される長いアニメーション フレームの量を最小限に抑えることができるためです。必要に応じて、値を大きくしたり小さくしたりできます。
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
重要な UI の更新中に長いアニメーション フレームを監視してスムーズさを改善
前述のように、長いアニメーション フレームのブロック時間が長い場合は、入力の応答性に問題がある可能性があります。ただし、スムーズにするには、長い duration
で長いアニメーション フレームを確認する必要があります。
ノイズが非常に多い場合は、次のようなパターンで測定ポイントをキーポイントに制限することをおすすめします。
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
if (measureImportantUIupdate) {
for (const entry of list.getEntries()) {
if (entry.duration > REPORTING_THRESHOLD_MS) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
async function doUIUpdatesWithMeasurements() {
measureImportantUIupdate = true;
await doUIUpdates();
measureImportantUIupdate = false;
}
最も長いアニメーション フレームを観察する
サイトによっては、ビーコンで送信する必要があるデータ量を減らすために、しきい値を設定するのではなく、最も長いアニメーション フレーム(またはフレーム)に関するデータを収集することもできます。そのため、ページで長いアニメーション フレームがいくつ発生しても、最も長いアニメーション フレーム(5 フレーム、10 フレームなど、絶対に必要なフレーム数)のデータのみがビーコンで送信されます。
MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];
const observer = new PerformanceObserver(list => {
longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
(a, b) => b.blockingDuration - a.blockingDuration
).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });
これらの戦略を組み合わせることもできます。たとえば、インタラクション時間が 100 ミリ秒を超える LoAF のうち、最もパフォーマンスの悪い 10 個のみを確認します。
適切なタイミング(visibilitychange
イベントが理想的)で、アナリティクスにビーコンを返します。ローカルテストでは、console.table
を定期的に使用できます。
console.table(longestBlockingLoAFs);
長いアニメーション フレームの一般的なパターンを特定する
別の方法として、長いアニメーション フレーム エントリで最も多く出現する一般的なスクリプトを確認することもできます。データはスクリプトと文字位置レベルで報告され、違反を繰り返すユーザーを特定できます。
これは、パフォーマンスの問題の原因となるテーマやプラグインを複数のサイトで特定できるカスタマイズ可能なプラットフォームに特に適しています。
長いアニメーション フレーム内の一般的なスクリプト(またはサードパーティ オリジン)の実行時間を合計してレポートすることで、サイトまたはサイトのコレクション全体で長いアニメーション フレームの発生に共通して影響している要因を特定できます。たとえば、URL を確認するには:
const observer = new PerformanceObserver(list => {
const allScripts = list.getEntries().flatMap(entry => entry.scripts);
const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
allScripts.filter(script => script.sourceURL === sourceURL)
]));
const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
sourceURL,
count: scripts.length,
totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
}));
processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
// Example here logs to console, but could also report back to analytics
console.table(processedScripts);
});
observer.observe({type: 'long-animation-frame', buffered: true});
出力の例を次に示します。
(index) |
sourceURL |
count |
totalDuration |
---|---|---|---|
0 |
'https://example.consent.com/consent.js' |
1 |
840 |
1 |
'https://example.com/js/analytics.js' |
7 |
628 |
2 |
'https://example.chatapp.com/web-chat.js' |
1 |
5 |
ツールで Long Animation Frames API を使用する
この API を使用すると、ローカル デバッグ用の追加のデベロッパー ツールも使用できます。Lighthouse や Chrome DevTools などのツールでは、低レベルのトレース詳細を使用してこのデータの大部分を収集できましたが、この高レベルの API を使用すると、他のツールもこのデータにアクセスできるようになります。
DevTools で長いアニメーション フレームのデータを確認する
performance.measure()
API を使用して、長いアニメーション フレームを DevTools に表示できます。このフレームは、パフォーマンス トレースの DevTools のユーザー タイミング トラックに表示され、パフォーマンス改善に重点を置くべき場所を示します。DevTools Extensibility API を使用すると、これらのイベントを独自のトラックに表示することもできます。
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
performance.measure('LoAF', {
start: entry.startTime,
end: entry.startTime + entry.duration,
detail: {
devtools: {
dataType: "track-entry",
track: "Long animation frames",
trackGroup: "Performance Timeline",
color: "tertiary-dark",
tooltipText: 'LoAF'
}
}
});
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
長期的には、長いアニメーション フレームは DevTools 自体に組み込まれる可能性がありますが、それまでの間は、前のコード スニペットを使用して表示できます。
上の図の最初のエントリは、ブラウザが複数のタスクを、タスクの間にレンダリングするのではなく、同じ長いアニメーション フレームでまとめて処理した場所を示しています。前述のように、優先度の高い入力タスクは存在しないものの、タスクのキューがある場合に発生することがあります。最初の長いタスクには、完了するレンダリング アップデートがいくつかあります(完了しないと、現在の長いアニメーション フレームはその後でリセットされ、次のタスクで新しいフレームが開始されます)。しかし、ブラウザは、そのレンダリングをすぐに実行するのではなく、いくつかの追加タスクを処理してから、長いレンダリング タスクを実行し、長いアニメーション フレームを終了しました。これは、長いタスクだけでなく、DevTools で長いアニメーション フレームを確認して、レンダリングの遅延を特定する方法の有用性を示しています。
他のデベロッパー ツールで長いアニメーション フレームデータを使用
Web Vitals 拡張機能が、ロギング概要のデバッグ情報に値を表示して、パフォーマンスの問題を診断できるようになりました。
また、各 INP コールバックと各インタラクションの長いアニメーション フレームデータも表示されるようになります。
自動テストツールで長いアニメーション フレームデータを使用する
同様に、CI/CD パイプラインの自動テストツールは、さまざまなテストスイートを実行しながら長いアニメーション フレームを測定することで、潜在的なパフォーマンスの問題の詳細を表示できます。
よくある質問
この API に関するよくある質問を以下に示します。
Long Tasks API を拡張または反復処理しないのはなぜですか?
これは、潜在的な応答性の問題に関する同様の測定値(最終的には異なる測定値)を報告する別の方法です。既存の Long Tasks API に依存するサイトが引き続き機能するようにし、既存のユースケースが中断されないようにすることが重要です。
Long Tasks API は、LoAF の一部機能(アトリビューション モデルの改善など)を利用できる可能性がありますが、タスクではなくフレームに焦点を当てることで、既存の Long Tasks API とは根本的に異なる API になるという多くのメリットがあります。
スクリプト エントリがないのはなぜですか?
これは、長いアニメーション フレームが JavaScipt ではなく、レンダリング作業の負荷が高いことが原因であることを示している可能性があります。
また、長いアニメーション フレームが JavaScript によるものであるにもかかわらず、前述のさまざまなプライバシー上の理由(主に、JavaScript がページ所有のものではない)によりスクリプトの帰属を提供できない場合にも発生することがあります。
スクリプト エントリはあるのに、ソース情報がないか、制限されているのはなぜですか?
これは、適切な参照元がないなど、さまざまな理由で発生する可能性があります。
スクリプト情報も、no-cors cross-origin
スクリプトの場合は sourceURL
(リダイレクトを除く)のみに制限され、sourceFunctionName
は空の文字列、sourceCharPosition
は -1
になります。この問題は、<script>
呼び出しに crossOrigin = "anonymous"
を追加して CORS を使用してスクリプトを取得することで解決できます。
たとえば、ページに追加するデフォルトの Google タグ マネージャー スクリプトは次のとおりです。
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->
j.crossOrigin = "anonymous"
を追加して拡張すると、GTM に完全なアトリビューションの詳細を提供できます。
これは Long Tasks API に代わるものですか?
長いタスクの測定には Long Animation Frames API の方が優れた完全な API ですが、現時点では Long Tasks API を非推奨にする予定はありません。
フィードバックを求めている
フィードバックは GitHub の問題リストで送信できます。また、Chrome の実装 API のバグは Chrome の問題トラッカーで報告できます。
まとめ
Long Animation Frames API は、以前の Long Tasks API よりも多くのメリットが期待できる、魅力的な新しい API です。
INP で測定される応答性の問題に対処するための重要なツールであることが実証されています。INP は最適化が難しい指標です。この API は、デベロッパーが問題を簡単に特定して対処できるように、Chrome チームが検討している方法の一つです。
Long Animation Frames API の適用範囲は INP だけではありません。ウェブサイトのユーザー エクスペリエンスの全体的なスムーズさに影響する可能性のある、更新の遅延の他の原因を特定するのにも役立ちます。