入力遅延とは何か、インタラクティビティを向上させるための遅延を減らす手法について説明します。
ウェブ上のインタラクションは複雑で、ブラウザ内でさまざまなアクティビティが発生してインタラクションが駆動されます。ただし、イベント コールバックの実行が開始される前に、入力遅延が発生するという共通点があります。このガイドでは、入力遅延とは何か、ウェブサイトのインタラクションを高速化するために入力遅延を最小限に抑える方法について説明します。
入力遅延とは何ですか?
入力遅延とは、ユーザーが最初にページを操作したとき(画面のタップ、マウスのクリック、キーの押下など)から、その操作のイベント コールバックが実行されるまでの時間です。すべてのインタラクションは、ある程度の入力遅延から始まります。
入力遅延の一部は避けられません。オペレーティング システムが入力イベントを認識してブラウザに渡すには、常に一定の時間がかかります。ただし、入力遅延のその部分はほとんど気づかれないことが多く、ページ自体で発生する他のことが原因で入力遅延が長くなり、問題が発生することがあります。
入力遅延の考え方
一般的に、ユーザーのデバイスに関係なく、ウェブサイトが Interaction to Next Paint(INP)指標の「良好」な基準値を満たす可能性を最大限に高めるには、インタラクションのすべての部分をできるだけ短くする必要があります。入力遅延を抑えることは、そのしきい値を満たすための 1 つの要素にすぎません。
そのため、INP の「良好」のしきい値を満たすために、可能な限り短い入力遅延を目指す必要があります。ただし、入力遅延を完全に解消することはできません。ユーザーがページを操作しようとしているときにメインスレッドの過剰な処理を避けていれば、入力遅延は問題が起こらない程度に低くなります。
入力遅延を最小限に抑える方法
前述のとおり、入力遅延は避けられないものもありますが、避けられるものもあります。入力の遅延が長い場合は、次の点を考慮してください。
メインスレッドの過剰な処理をトリガーする定期的なタイマーを避ける
JavaScript には、入力遅延の原因となる setTimeout と setInterval の 2 つのタイマー関数がよく使用されます。2 つの違いは、setTimeout が指定された時間の後に実行されるコールバックをスケジュールすることです。一方、setInterval は、n ミリ秒ごとにコールバックを永久に実行するようにスケジュールします。または、clearInterval でタイマーが停止するまで実行します。
setTimeout 自体は問題ではありません。実際、長いタスクを回避するのに役立ちます。ただし、タイムアウトが発生したタイミングと、タイムアウト コールバックの実行中にユーザーがページを操作しようとしたかどうかによって異なります。
また、setTimeout はループまたは再帰的に実行できます。この場合、setInterval のように動作しますが、前のイテレーションが完了するまで次のイテレーションをスケジュールしないことが望ましいです。この場合、setTimeout が呼び出されるたびにループがメインスレッドに処理を譲りますが、コールバックが過剰な処理を行わないように注意する必要があります。
setInterval は一定の間隔でコールバックを実行するため、インタラクションの妨げになる可能性がはるかに高くなります。これは、setTimeout 呼び出しの単一インスタンスは、ユーザー操作の妨げになる可能性がある 1 回限りのコールバックであるのに対し、setInterval は繰り返し発生するため、操作の妨げになる可能性がはるかに高く、操作の入力遅延が増加するためです。
setInterval 呼び出しによって登録されたタイマー。入力遅延が追加されると、インタラクションのイベント コールバックが、本来よりも遅れて実行されます。タイマーがファーストパーティ コードで発生している場合は、タイマーを制御できます。必要かどうかを評価するか、できるだけ作業を減らすようにしてください。ただし、サードパーティ スクリプトのタイマーは別の話です。多くの場合、サードパーティ スクリプトの動作を制御することはできません。サードパーティ コードのパフォーマンスの問題を解決するには、多くの場合、関係者と協力して、特定のサードパーティ スクリプトが必要かどうかを判断し、必要であれば、サードパーティ スクリプト ベンダーに連絡して、ウェブサイトで発生する可能性のあるパフォーマンスの問題を解決するために何ができるかを判断する必要があります。
長時間実行されるタスクを回避する
入力の遅延を軽減する 1 つの方法は、長いタスクを避けることです。メインスレッドの作業が過剰で、インタラクション中にメインスレッドがブロックされると、長いタスクが完了する前に、入力遅延が長くなります。
タスクで実行する作業量を最小限に抑えること(メインスレッドで実行する作業は常に最小限に抑えるようにしてください)に加えて、長いタスクを分割することで、ユーザー入力に対する応答性を高めることができます。
インタラクションの重複に注意する
INP の最適化で特に難しいのは、インタラクションが重複している場合です。インタラクションの重複とは、ある要素を操作した後、最初のインタラクションで次のフレームがレンダリングされる前に、ページを再度操作することです。
インタラクションの重複の原因は、ユーザーが短時間に多くのインタラクションを行ったという単純なものである可能性があります。これは、ユーザーがフォーム フィールドに入力するときに発生することがあります。この場合、非常に短い時間内に多くのキーボード操作が行われる可能性があります。キーイベントの処理が特に高負荷な場合(バックエンドにネットワーク リクエストを行うオートコンプリート フィールドの一般的なケースなど)、次の 2 つのオプションがあります。
- デバウンス入力を使用して、特定の期間にイベント コールバックが実行される回数を制限することを検討してください。
AbortControllerを使用して送信fetchリクエストをキャンセルし、メインスレッドがfetchコールバックの処理で混雑しないようにします。注:AbortControllerインスタンスのsignalプロパティを使用して、イベントを中止することもできます。
重複するインタラクションによる入力遅延の増加のもう 1 つの原因は、コストの高いアニメーションです。特に、JavaScript のアニメーションは requestAnimationFrame 呼び出しを多数発生させる可能性があり、ユーザー操作の妨げになることがあります。これを回避するには、可能な限り CSS アニメーションを使用して、コストのかかるアニメーション フレームのキューイングを避けます。ただし、この場合は、アニメーションが主に GPU とコンポジタ スレッドで実行され、メインスレッドで実行されないように、非コンポジット アニメーションを避けるようにしてください。
まとめ
入力遅延はインタラクションの実行にかかる時間の大部分を占めていないかもしれませんが、インタラクションの各部分には短縮できる時間がかかっていることを理解しておくことが重要です。入力遅延が長い場合は、入力遅延を短縮できる可能性があります。タイマー コールバックの繰り返しを避け、長いタスクを分割し、インタラクションの重複の可能性を認識することで、入力遅延を減らし、ウェブサイトのユーザーのインタラクティビティを向上させることができます。
Unsplash の Erik Mclean によるヒーロー画像。