入力遅延を最適化する

入力遅延の概要と、入力遅延を短縮してインタラクティビティを高速化する方法をご紹介します。

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

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

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

入力遅延の一部は避けられません。オペレーティング システムが入力イベントを認識してブラウザに渡すまでには常にある程度の時間がかかります。ただし、多くの場合、入力遅延のその部分はそれほど顕著ではありません。また、ページ自体で発生する他の要因によって、入力遅延が長くなり、問題が発生することもあります。

入力遅延について考える

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

したがって、INP の「良好」な基準を満たすために、入力遅延をできるだけ短くする必要があります。ただし、入力の遅延を完全に排除することはできません。ユーザーがページを操作しようとしているときに、メインスレッドで過度の処理が行われないようにすれば、問題を回避できるほど入力遅延を短くできます。

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

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

過度のメインスレッド処理を開始する繰り返しタイマーを回避する

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

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

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

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

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

タイマーがファーストパーティ コード内で発生している場合は、デベロッパーが制御できます。その作業が必要かどうかを評価します。または、作業量をできるだけ減らすよう最善を尽くします。ただし、サードパーティ スクリプトのタイマーについては状況が異なります。サードパーティ スクリプトの動作を制御できないことが多く、サードパーティ コードのパフォーマンスの問題を解決するには、関係者と連携して特定のサードパーティ スクリプトが必要なかどうかを判断し、必要な場合はサードパーティ スクリプト ベンダーに連絡して、ウェブサイトで発生する可能性のあるパフォーマンスの問題を解決するために何ができるかを判断する必要があります。

長いタスクを避ける

長い入力遅延を軽減する方法の一つは、長いタスクを避けることです。操作中にメインスレッドをブロックするメインスレッドの作業が多すぎると、長いタスクが完了する前に入力の遅延が増加します。

タスクが入力遅延を延長する時間の可視化。上図では、長時間のタスクの実行直後にインタラクションが発生しているため、入力が大幅に遅延し、イベント コールバックが想定よりも大幅に遅れて実行されています。一番下では、ほぼ同時にインタラクションが発生しますが、長いタスクは yield によっていくつかの小さなタスクに分割されるため、インタラクションのイベント コールバックをより迅速に実行できます。
タスクが長すぎてブラウザが操作に十分に迅速に応答できない場合と、長いタスクを小さなタスクに分割した場合の、インタラクションへの影響の可視化。

タスクで行う処理の量を最小限に抑える(メインスレッドでできるだけ少ない処理を行うように常に心がけてください)だけでなく、長いタスクを分割することで、ユーザー入力に対する応答性を改善できます。

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

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

タスクが重なり、入力遅延が長くなる可能性がある場合の図。この図では、クリック操作がキーダウン操作と重なって、キーダウン操作の入力遅延が長くなっています。
Chrome の DevTools のパフォーマンス プロファイラで、2 つの同時インタラクションの可視化。最初のクリック操作でのレンダリング処理により、その後のキーボード操作で入力遅延が発生します。

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

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

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

まとめ

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

Unsplash のヒーロー画像(Erik Mclean 撮影)。