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