入力遅延を最適化する

入力遅延とは何か、そしてインタラクティビティを高めるために入力遅延を短縮する手法について説明します。

ウェブ上のインタラクションは複雑で、ブラウザでさまざまなアクティビティが発生してインタラクションが促進されます。ただし、これらすべてに共通しているのは、イベント コールバックの実行が開始される前に入力遅延が発生することです。このガイドでは、入力遅延とは何か、また、ウェブサイトのインタラクションを高速化するために、入力遅延を最小限に抑える方法について説明します。

入力遅延とは

入力遅延とは、ユーザーが最初にページを操作したとき(画面のタップ、マウスのクリック、キーの押下など)から、その操作のイベント コールバックが実行されるまでの期間です。すべてのインタラクションは、ある程度の入力遅延から始まります。

入力遅延の簡略化された可視化。左側には、マウスカーソルの線画があり、その後ろにスターバーストが描かれています。これは、インタラクションの開始を表しています。右側には歯車の線画があり、インタラクションのイベント ハンドラが実行を開始するタイミングを示しています。その間のスペースは、中かっこで入力遅延として示されています。
入力遅延の仕組み。オペレーティング システムが入力されると、インタラクションが開始される前にブラウザに渡される必要があります。これには一定の時間がかかり、既存のメインスレッドの処理によってさらに時間がかかることがあります。

入力遅延の一部は避けられません。オペレーティング システムが入力イベントを認識してブラウザに渡すには、常に一定の時間がかかります。しかし、入力遅延のその部分は多くの場合、気付かれることさえありません。ページ自体で発生する他のことが原因で、入力遅延が長くなり、問題を引き起こす可能性があります。

入力遅延の考え方

一般的に、ユーザーのデバイスに関係なく、ウェブサイトが Interaction to Next Paint(INP)指標の「良好」しきい値を満たす可能性を最大限に高めるには、インタラクションのすべての部分をできるだけ短くする必要があります。入力遅延を抑えることは、このしきい値を満たすための一要素にすぎません。

そのため、INP の「良好」のしきい値を満たすには、入力遅延をできるだけ短くすることを目指す必要があります。ただし、入力遅延を完全に排除することはできません。ユーザーがページを操作しようとしているときにメインスレッドの過剰な処理を回避している限り、入力遅延は問題が発生しない程度に低く抑えられます。

入力遅延を最小限に抑える方法

前述のように、一部の入力遅延は避けられませんが、一方で、一部の入力遅延は回避可能です。入力遅延が長い場合は、次の点を考慮してください。

メインスレッドで過剰な処理を起動する繰り返しタイマーを避ける

JavaScript でよく使用されるタイマー関数には、入力遅延の原因となる setTimeout と setInterval の 2 つがあります。2 つの違いは、setTimeout は指定された時間の後に実行されるコールバックをスケジュールすることです。setInterval は、n ミリ秒ごとにコールバックを実行するようにスケジュールします。これは、clearInterval でタイマーが停止されるまで、永続的に実行されます。

setTimeout 自体は問題ではありません。実際、長いタスクを回避するのに役立ちます。ただし、これはタイムアウトが発生するタイミングと、タイムアウト コールバックの実行時にユーザーがページを操作しようとするかどうかによって異なります。

また、setTimeout はループまたは再帰的に実行できます。この場合、setInterval のように動作しますが、前のイテレーションが完了するまで次のイテレーションをスケジュールしないことが望ましいです。これは、setTimeout が呼び出されるたびにループがメインスレッドに譲ることを意味しますが、コールバックが過剰な処理を行わないように注意する必要があります。

setInterval は一定の間隔でコールバックを実行するため、インタラクションの妨げになる可能性がはるかに高くなります。これは、setTimeout 呼び出しの単一インスタンス(ユーザー操作の妨げになる可能性がある 1 回限りのコールバック)とは異なり、setInterval の繰り返しという性質により、操作の妨げになる可能性が高く、操作の入力遅延が増加するためです。

入力遅延を示す Chrome DevTools のパフォーマンス プロファイラのスクリーンショット。タイマー関数によって起動されたタスクが、ユーザーがクリック操作を開始する直前に発生します。ただし、タイマーによって入力遅延が延長され、インタラクションのイベント コールバックが通常よりも遅れて実行されます。
Chrome DevTools のパフォーマンス パネルに表示されているように、以前の setInterval 呼び出しによって登録されたタイマーが入力遅延の原因となっています。入力遅延が追加されると、インタラクションのイベント コールバックが通常よりも遅れて実行されます。

タイマーがファーストパーティ コードで発生している場合は、タイマーを制御できます。それらが必要かどうかを評価するか、それらの作業をできるだけ減らすようにしてください。ただし、サードパーティ スクリプトのタイマーは別の話です。多くの場合、サードパーティ スクリプトの動作を制御することはできません。サードパーティ コードのパフォーマンスの問題を修正するには、多くの場合、関係者と協力して、特定のサードパーティ スクリプトが必要かどうかを判断します。必要な場合は、サードパーティ スクリプト ベンダーに連絡して、ウェブサイトで発生する可能性のあるパフォーマンスの問題を修正するために何ができるかを判断します。

長いタスクを回避する

長い入力遅延を軽減する方法の一つは、長いタスクを回避することです。メインスレッドの処理が多すぎて、インタラクション中にメインスレッドがブロックされると、長いタスクが完了する前に、インタラクションの入力遅延が増加します。

長いタスクが入力遅延をどの程度延長するかを視覚化したもの。上部では、1 つの長いタスクが実行された直後にインタラクションが発生し、大幅な入力遅延が発生して、イベント コールバックが本来よりもかなり遅れて実行されます。下部では、インタラクションがほぼ同時に発生していますが、長いタスクは yield によって複数の小さなタスクに分割されているため、インタラクションのイベント コールバックをはるかに早く実行できます。
タスクが長すぎてブラウザがインタラクションに迅速に応答できない場合と、長いタスクを小さなタスクに分割した場合のインタラクションの可視化。

タスクで行う作業量を最小限に抑える(メインスレッドで行う作業をできるだけ少なくするよう常に努める)だけでなく、長いタスクを分割することで、ユーザー入力に対する応答性を向上させることができます。

インタラクションの重複に注意する

INP の最適化で特に難しいのは、インタラクションが重複している場合です。インタラクションの重複とは、1 つの要素を操作した後、最初のインタラクションが次のフレームをレンダリングする前に、ページに対して別のインタラクションを行うことです。

タスクが重複して長い入力遅延が発生する状況の図。この図では、クリック インタラクションが keydown インタラクションと重複し、keydown インタラクションの入力遅延が増加しています。
Chrome の DevTools のパフォーマンス プロファイラに表示された、2 つの同時インタラクションの可視化。最初のクリック操作のレンダリング作業により、後続のキーボード操作で入力遅延が発生します。

インタラクションの重複の原因は、ユーザーが短時間に多くのインタラクションを行ったという単純なものである可能性があります。これは、ユーザーがフォーム フィールドに入力するときに発生することがあります。この場合、非常に短い時間で多くのキーボード操作が発生する可能性があります。キーイベントの処理が特に高負荷な場合(バックエンドにネットワーク リクエストを送信する予測入力フィールドの一般的なケースなど)、いくつかのオプションがあります。

  • 入力のデバウンスを検討して、一定期間にイベント コールバックが実行される回数を制限します。
  • AbortController を使用して、送信される fetch リクエストをキャンセルします。これにより、fetch コールバックの処理でメインスレッドが混雑するのを防ぐことができます。注: AbortController インスタンスの signal プロパティを使用して、イベントを中止することもできます。

インタラクションの重複による入力遅延の増加のもう一つの原因は、負荷の高いアニメーションです。特に、JavaScript のアニメーションでは、多くの requestAnimationFrame 呼び出しが発生し、ユーザー インタラクションの妨げになる可能性があります。これを回避するには、可能な限り CSS アニメーションを使用して、負荷の高いアニメーション フレームがキューに登録されないようにします。ただし、その場合は、合成されていないアニメーションの使用を避けるようにして、アニメーションがメインスレッドではなく、主に GPU スレッドとコンポジタ スレッドで実行されるようにします。

まとめ

入力遅延は、インタラクションの実行にかかる時間の大部分を占めるわけではありませんが、インタラクションのすべての部分で、短縮できる時間が費やされていることを理解することが重要です。入力遅延が長い場合は、遅延を短縮できる可能性があります。繰り返し発生するタイマー コールバックを回避し、長いタスクを分割し、インタラクションの重複の可能性を認識することで、入力遅延を減らし、ウェブサイトのユーザーのインタラクティブ性を高めることができます。