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