FID（First Input Delay）

# FID（First Input Delay）
## とは何か
[`FID（First Input Delay）`](https://web.dev/lcp/)とは、「サイトの双方向性と反応性に対するユーザーの第一印象[^1]」を計測することを企図した指標。

[^1]: この「第一印象」について、wev.devの[`FID`の紹介記事](https://web.dev/fid/)では「どれだけ速くサイトが表示されるかについてのユーザへの第一印象は[First Contentful Paint (FCP)](https://web.dev/fcp/)で計測できる。しかしどんなにスクリーン上のピクセルへの描画が速くてもそれはストーリー（＝第一印象を良くする）の単なる一部でしかない。同様に重要なこととしてどれだけそれらのピクセルに対してユーザが対話（≒操作）を試みたときへの反応性が挙げられる。」と説明している。

具体的には、「ユーザが初めにページと対話（≒操作）したときからブラウザが実際にその対話（≒操作）への反応としてイベントハンドラの処理を開始できるまでの時間」とされている。

`FID`の目標タイムとしては、100ミリ秒以内を[目指すべきとされる](https://web.dev/fid/#what-is-a-good-fid-score)。
また、このタイムをほとんどのユーザで体験できることを目指すのであれば、ページロードにおいて75[パーセンタイル](https://www.google.co.jp/search?q=%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%AB)に当たるところが良い閾値となるとのこと。
なお、この「100ミリ秒以内」という数値について、Webに限らず工業デザイン一般において人間が遅延を感じ始める時間（応答時間の目標上限値）として[知られている](https://www.google.co.jp/search?q=%E6%93%8D%E4%BD%9C+%E9%81%85%E5%BB%B6+%E6%84%9F%E8%A6%9A+100%E3%83%9F%E3%83%AA%E7%A7%92)ものでもある。

## もっと詳しい話
### では、その遅延はどうして起こるのか
一般には、「何かしらの処理が原因でメインスレッド[^2]がビジーになっていて、まだユーザの操作に反応できてない」というのが考えられる。

そして、そのよくある原因の1つとしてブラウザがWebアプリケーションのバカでかいJavaScirptファイルを実行に向けて解釈している最中であるが多い。そしてこの場合、そのでっかいJavaScript内にイベントハンドラが書かれているかもしれないので、ブラウザは何ひとつイベントリスナーを走らせることができない。
（ブラウザ「だからいまその『何をすべきか』を理解してる最中かもだから、ちょっとまって！！」）

[^2]: メインスレッドとは、ブラウザでページの描画などを担っている、メインのスレッド。とはいえ、WebWorkerなどでマルチスレッド化していない限りすべての処理がこのスレッドで行われているので、そういうマルチスレッド下でない限り「現在のページのスレッド」って理解でいい。

もちろん上記の例以外にも、何かしらの重い処理でメインスレッドがビジーになれば、イベントハンドラーの実行が遅れ、遅延の原因となりうるので、なるべくメインスレッドを空けておく、アプリケーションのJSが大きくなりすぎたときは[画面・機能ごとなどに分割](https://www.google.co.jp/search?q=code+splitting)して負荷を時間的に分散する、などで適宜適切な対策を講じると良い。

### ところで、操作に対して何もイベントリスナーを持ってないときはどうなるの？
`FID`は、入力イベントが受理されてからメインスレッドが次のアイドルタイムに入るまでの時間を計測するが、これは`FID`が**何一つイベントリスナーを登録されていなくても**計測されるということになる。その理由としてなぜなら、多くのユーザインタラクションがイベントリスナーを必要としないが、挙動にはメインスレッドがアイドル状態になる必要があるから、[だそうです](https://web.dev/fid/#what-if-an-interaction-doesn't-have-an-event-listener)。

例えば、下記の全てのHTML要素がユーザインタラクションに先立って実行中のメインスレッドのタスクの完了を待つ必要ある。

- テキストフィールド、チェックボックス、そしてラジオボタン（`<input>`, `<textarea>`）
- 選択ドロップダウン（`<select>`）
- リンク（`<a>`）

### なぜ初めの入力だけ遅延を気にするのか
Webページ/アプリケーションの入力遅延は（初回に限らず）いかなる時でもユーザエクスペリエンスの悪化要因となるが、ではなぜ初回の入力遅延だけ特に重要視されているのか。
`FID`を紹介する記事では、以下のように[説明されて](https://web.dev/fid/#why-only-consider-the-first-input)いる。

> - The first input delay will be the user's first impression of your site's responsiveness, and first impressions are critical in shaping our overall impression of a site's quality and reliability.
> - The biggest interactivity issues we see on the web today occur during page load. Therefore, we believe initially focusing on improving site's first user interaction will have the greatest impact on improving the overall interactivity of the web.
> - The recommended solutions for how sites should fix high first input delays (code splitting, loading less JavaScript upfront, etc.) are not necessarily the same solutions for fixing slow input delays after page load. By separating out these metrics we'll be able to provide more specific performance guidelines to web developers.

- _初回の入力遅延はユーザにとってサイトの応答性に対する第一印象となりやすく、そして第一印象はサイトのクオリティや信頼性などの全体の印象の形成に決定的（な影響を及ぼすもの）となる。_
- _我々が今日目にする最大の双方向性の問題はページロードの最中に起こる。それゆえ、まずはサイトの（表示）初期のユーザインタラクションの改善に着目することがWeb全体の双方向性の改善に大きなインパクトをもたらすだろうと信じている。_
- _（[コードスプリッティング](https://www.google.co.jp/search?q=code+splitting)や事前にロードされるJavaScriptの削減 等）高い初期入力遅延の改善に推奨されている手法が必ずしも読み込み後の入力遅延にも有効であるとは限らない。（しかし）これらの指標を分離することでより具体的なパフォーマンスガイドラインをWeb開発者に対して提供できるようになるだろう。_

### 何の操作が`FID`の対象となり、逆に何がそうでないか
`FID`は読み込み中のページの応答性を測定する指標であり、それゆえ、クリックやタップ、キー押下などの個々の操作による入力イベントにフォーカスしているに過ぎない。

その他のインタラクション、例えばスクロールやズーム、は継続的なアクションでありパフォーマンス上の成約とは完全に異なるものである（そしてまた、ブラウザはこれらを別スレッドで処理することでそれらに起因する遅延を隠蔽できていることもしばしばある）。

言い換えれば、`FID`は[`RAILパフォーマンスモデル`](https://web.dev/rail/)における`R(responsiveness)`に注目し、スクロールやズームは`A(animation)`のほうにより関係があり、そしてこれらのパフォーマンスクオリティは分離して評価されるべきである。

[だそうです](https://web.dev/fid/#what-counts-as-a-first-input)。

### もしユーザがサイト内で何一つ操作をしなかったら？
すべてのユーザが訪問したサイトで何かしら操作をするとは限らず、なんなら（前項に記載の通り）すべての操作が`FID`に関係しているわけではない。加えて、各ユーザの最初の操作についてもそれぞれタイミングの良し悪しがあったりする。
このことは、あるユーザは`FID`値がそもそもなかったり、また別のユーザは偶然良かったり、はたまた逆に悪かったりするということを意味する。
なので、`FID`を追って、レポートして、分析するということは、これまで慣れ親しんだ他の指標とは少し異なるかもしれないということになる。

この辺の問題への対処法は[後述](#fidデータの分析とレポート)。

### てかそもそもなんで入力「遅延」だけ気にするのか
上述してきたとおり、`FID`はイベント処理中の「遅延」のみを計測し、イベント処理そのものの処理時間やイベントハンドラによって起こるUI更新にブラウザがどれだけ時間をかけたかなどは計測されない。
これらの時間がユーザにとって重要であり、またユーザエクスペリエンスに間違いなく影響を及ぼすにもかかわらず`FID`に含まれていない理由は、開発者に対し実際にはユーザエクスペリエンスを悪化させるようなその場しのぎの対処法の実装を奨励することになりうるからだ。すなわち例えば、イベントに関連付けられたタスクをそれらから分離するために、イベントハンドラロジックを（`setTimeout()`や`requestAnimationFrame()`などを介した）非同期のコールバックでラップしたりなどである。こうなることは指標スコアの改善にはつながっても、ユーザが知覚する応答性は悪化する。
ところが、`FID`はイベント遅延において分析しうる要素のうちの「どれだけ遅延したか」のみを計測しているため、イベントサイクルについてより追跡したいと考える開発者に[Event Timing API](https://wicg.github.io/event-timing/)を使用した分析に導くことができる。
なお、[Event Timing API](https://wicg.github.io/event-timing/)を使用した分析手法については、web.devの[Custom metricsについての記事](https://web.dev/custom-metrics/#event-timing-api)が詳しい。

## `FID`の計測と分析
### `FID`が計測可能なライブラリ・ツール
- [web-vitals](https://github.com/GoogleChrome/web-vitals/)（npmライブラリ）
- [Web Vitals Chrome Extension](https://github.com/GoogleChrome/web-vitals-extension/)（Chrome拡張機能）
- [Lighthouse](https://developers.google.com/web/tools/lighthouse)および[Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools)
- [Chrome User Experience Report](https://developers.google.com/web/tools/chrome-user-experience-report)
- [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/)
- [Search Console (Core Web Vitals report)](https://support.google.com/webmasters/answer/9205520)

### JavaScriptで`FID`を測ってみる（測れてるとは言ってない）
JavaScriptでの`FID`の計測は、[`Event Timing API`](https://wicg.github.io/event-timing/)を使用する。
以下の例では、簡易的に[`PerformanceObserver`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver)に対して[`first-input`](https://wicg.github.io/event-timing/#sec-performance-event-timing)をリスンさせログをコンソールに出力している。

```js
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    const delay = entry.processingStart - entry.startTime;
    console.log('FID candidate:', delay, entry);
  }
}).observe({type: 'first-input', buffered: true});
```

【注意】: 正確な精度のFIDの計測にはもっと複雑なJavaScriptによる実装が必要。上記の例では`first-input`エントリの遅延時間をエントリの`startTime`と`processingStart`間のタイムスタンプ差分を取ることで`FID`とみなしており、ほとんどのケースでそうなるが、かならずしも全ての`first-input`エントリが`FID`の計測に用いるのに適切とは限らない。

#### `Event Timing API`と`FID`間の差異
- `first-input`エントリはページのロードがバックグラウンドで行われたものも対象とされるが、`FID`の計測では無視されなければならない。（→ 計測すべきでないものが誤計測される）
- `first-input`エントリはページが初期入力の発生に先立ってバックグラウンド化された場合でも対象とされるが、`FID`の計測ではこれも同様に無視されなければならない。（→ 同上）
- `first-input`エントリはブラウザの「戻る」/「進む」時にキャッシュから復元された場合はレポートされないが、`FID`の計測においてこれらはユーザエクスペリエンス上個別のページ訪問として計測されなければならない。（→ 計測されるべきものが計測落ちする）
- `Event Timing API`はiframe内で発生した入力をレポートしないが、正確な`FID`の計測ではこれらも考慮されなければならない。もしサブフレーム内でも`Event Timing API`によって`first-input`エントリによるレポートを生成し親フレームに集約させていればiframeを含む正確な`FID`の計測が可能（親フレーム側でもそれを許可＆受け取る必要あり）。

### 真・JavaScriptで`FID`を測ってみる（feat. `web-vitals`ライブラリ）
```js
import {getFID} from 'web-vitals';

// これで計測された**正確な**FIDがコンソールに出力されるようになる
getFID(console.log);
```
以上である。（なんだい？この簡単すぎて拍子抜けするコードは。）

なおセキュリティ上の理由で、この`getFID()`を使った方法でも、「クロスオリジンなiframe」のようなケースにおいて一部`FID`を計測できない場合がある。
詳細は`web-vitals`ライブラリの[Limitations](https://github.com/GoogleChrome/web-vitals#limitations)の項を参照のこと。

ちなみに、`FID`の正確な計測方法を知りたい場合、この[`getFID()`のソースコード](https://github.com/GoogleChrome/web-vitals/blob/master/src/getFID.ts)から確認できる。

### `FID`データの分析とレポート
前述の通り、`FID`値はブレることが予想されるため、FIDをレポートする際には、値分布に気を配り、より高い[パーセンタイル](https://www.google.co.jp/search?q=%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%AB)にフォーカスするのが重要となる。

全ての`CoreWebVitals`における[パーセンタイル選択](https://web.dev/defining-core-web-vitals-thresholds/#choice-of-percentile)のしきい値は75だが、こと
`FID`については、サイト内でファーストエクスペリエンスが特に劣悪だったユーザに対応するであろう95〜90[パーセンタイル](https://www.google.co.jp/search?q=%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%AB)が推奨される。そうすることで、最も改善を必要とする領域があらわになると思われる。

これは、もしデバイスカテゴリやタイプごとにレポートを分類しても、真と言える。例えば、もしレポートをデスクトップとモバイルに分けてレポートしたとしても、`FID`値はデスクトップで最もケアすべきは95〜90[パーセンタイル](https://www.google.co.jp/search?q=%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%AB)のユーザとなるし、またモバイルにおいても最もケアすべきは95〜90[パーセンタイル](https://www.google.co.jp/search?q=%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%AB)のユーザとなるからだ。

## `FID`を改善するには
`Lighthouse`などのパフォーマンス監査ツールで検査してみて、提案された改善案の中で[この辺](https://web.dev/lighthouse-performance/#opportunities)あたりで手を付けられそうなものがないか試してみる。
特に、（`FID`がfield metric[^3]な指標、 `Lighthouse`がlab metric[^4]なツールであるという違いがあるが、）`Lighthouse`が診断結果として提案する[Total Blocking Time (TBT)](https://web.dev/tbt/)の改善ガイダンスは`FID`と同様なので参考にすると良さそう。

[^3]: field metricとは、実際のユーザ環境下で計測される/されたということ。
[^4]: lab metricとは、ツール下で環境を制限・制御する形でシミュレートして計測される/されたということ。

もし`FID`の改善手法をより深堀りしたいなら、web.devの[Optimize FID](https://web.dev/optimize-fid/)の記事が詳しい。
また、`FID`の改善につながる個々のパフォーマンステクニックについて知りたいなら、以下が参考になる。

- [Reduce the impact of third-party code - web.dev](https://web.dev/third-party-summary/)
- [Reduce JavaScript execution time - web.dev](https://web.dev/bootup-time/)
- [Minimize main thread work - web.dev](https://web.dev/mainthread-work-breakdown/)
- [Keep request counts low and transfer sizes small - web.dev](https://web.dev/resource-summary/)


## 参照
- [First Input Delay (FID) - web.dev](https://web.dev/fid/)