Webページのリソース"非最適化"によるPageSpeed Insightsへの詳細な影響調査

# 2020年6月3日追記

本家レポートより**PageSpeed Insightsのスコア改善が捗る裏レポートツール**を公開しました。合わせてご参考ください。
https://simulate.site/cheatspeed-insights/

この記事はLighthouse 5.6に準拠しています。Lighthouse 6.0への変更についてはこちらの記事などをご参考ください。
[PageSpeed Insightsのスコア大変動か？ Lighthouse 6 で変わる採点ルールを先取りチェック！ \- アイデアマンズブログ](https://blog.ideamans.com/2020/03/pagespeed-lighthouse-6-draft.html)

# リソースの非最適化によるPageSpeed Insightsのスコアを左右する要因を検証

通常、Webページの各種リソースの最適化や応答時間を短縮してパフォーマンスを向上させますが、ここではPageSpeed Insightsがそれらをどう評価するか、逆に`非最適化`することで検証してみました。

# 結論

リソースの条件を悪化させると、次のようにスコアとその構成要素が変化します。

| 　                                   | スコア | SPX※ | FCP | FMP | TTI | FCI※ |
|--------------------------------------|--------|-----|-----|-----|-----|-----|
| オリジナル                           | 100    | 100 | 100 | 100 | 100 | 100 |
| HTMLの応答遅延(9秒)                  | 74     | 2   | 100 | 100 | 100 | 100 |
| HTMLの重量化(約2MB)                  | 10     | 6   | 1   | 1   | 20  | 12  |
| CSSの応答遅延(9秒)                   | 74     | 2   | 100 | 100 | 100 | 100 |
| CSSの重量化(約2MB)                   | 10     | 6   | 1   | 1   | 20  | 12  |
| 画像の応答遅延(9秒)                  | 74     | 3   | 100 | 100 | 100 | 100 |
| 画像の重量化(約2MB)                  | 99     | 96  | 100 | 100 | 100 | 100 |
| JavaScriptの応答遅延(9秒)            | 99     | 96  | 100 | 100 | 100 | 100 |
| JavaScriptの重量化(約2MB)            | 73     | 100 | 100 | 100 | 18  | 100 |
| JavaScriptの重量化(約2MB)+headに配置 | 7      | 1   | 0   | 0   | 17  | 10  |
| JavaScriptのロングタスク化           | 53     | 100 | 100 | 100 | 0   | 0   |

※SPX: スピード指標 / ※FCI: 最初のCPUアイドル

* 通信中のデータ圧縮(`Content-Encoding`）はなし
* モバイル端末としてテスト

# ダミーページ

こんな感じの極めてシンプルなダミーページを用意します。

```html
<!doctype html>
<html>
  <head>
    <title>テストページ</title>
    <link rel="stylesheet" href="css/normal.css">
    <link rel="stylesheet" href="webfont/normal.css">
  </head>
  <body>
    <h1>Lighthouse Performance Test</h1>
    <img src="images/normal.jpg">
    <p>HTML・CSS・JavaScript・WebFontのPageSpeed Insights(Lighthouse Performance)への影響を比較検証します。</p>
    <script src="js/normal.js"></script>
  </body>
</html>
```

ブラウザで見るとこんな感じです。

<img width="380" alt="テストページ.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35178/0b94f7cf-ff11-d099-ea17-4e1514272ba8.png">

PageSpeed Insightsでスコアを測ると、当然100点となります。

以前、こんな実験も行いました。今回は因果関係をもう少し細かくしてみる試みです。

[超シンプルなページでPageSpeedスコア0点を意図的にとる方法 - Qiita](https://qiita.com/miyanaga/items/37f89a0e99597b479817)

# HTML関連

## HTMLの応答を9秒遅延させる

単純に9秒Sleepさせます。なぜ9秒かと言うと、10秒だとタイムアウトするからです。

これは以前実験したのですが、ドキュメントTTFBの遅延は、とても重要なのですが`スピード指標`にしか影響しません。

[PageSpeed InsightsでドキュメントTTFBはSpeedIndexにしか影響しない - Qiita](https://qiita.com/miyanaga/items/838478d5a559dd585972)

## HTMLを約2MBに重量化する

HTMLに非表示の`div`要素を多数追加し、サイズを約2MBまで膨張させます。なぜ2MBかというと、モバイル端末としてのテストは通信速度が1.6Mbpsにエミュレートされるので、2MBだと大体10秒くらいの読み込み時間を要するからです。

これはガッツリすべての項目が下がりました。レンダリング初期段階で大きな遅延が発生するからです。

JavaScriptは変更していないのに、それらの評価系である`TTI`と`FCI`も低下しています。これは`TTI`が`FCP`、`FCI`が`FMP`を計算の基準としているからで、道連れを食らった結果です。

# CSS関連

HTMLと同様に、CSSの応答を9秒遅らせるケースと、CSSをダミーのセレクタで2MBに膨張させたケースです。

CSSを2MBに膨張させると、HTMLの膨張とほぼ同じ結果となりました。CSSの読み込み中もレンダリングが停止するからです。

一方、CSSの応答を遅らせるケースでは`SPX`にのみ影響があります。ダウンロードが開始されたどうかが評価に影響するのが興味深いです。

# 画像関連

画像データのレスポンスをサーバー上でのSleepにより9秒遅らせるケースと、解像度を大きく上げて2MB程度までデータサイズを膨張させたケースです。

画像の応答が遅いと`SPX`が大きく低下しますが、画像データが膨張した場合はスコアの低下がほとんどありません。こちらもファーストビューの描画を評価する`SPX`には影響がありそうなものですが、予想外の結果でした。

# JavaScript関連

## JavaScriptの応答を9秒遅らせる

ダウンロードの開始(JavaScriptのTTFB)をサーバー上で9秒遅らせても、スコアにほとんど影響がありません。CSSのように、リソースのダウンロードが始まるまでが遅いことと、始まってからが遅いことには評価の違いがあります。

この結果は意外でした。応答が始まらないということは、サーバー側のタイムアウトの可能性があるものとして、評価対象のタイムラインに乗ってこない…という感じでしょうか。

ただ、CSSやJavaScriptのような静的リソースが応答遅延するというのはレアケースだと思うので、今後なにかの機会にまた調べようと思います。

## JavaScriptを約2MBに重量化する

ダミーの`function`を多数追加してデータサイズを膨張させます。`TTI`は悪化していますが、表示系の評価指標は無傷です。これは`script`要素がHTMLの最下部であり、レンダリングがブロックされるものの、ページの表示に関わる処理はほとんど完了しているからでしょう。

使ってないJavaScriptは積極的に削除しないといけません。

同じJavaScriptの負荷を評価する`FCI`に影響がないのも予想外でした。

仮説のひとつは、`TTI`はネットワークコネクションの沈静化も計測している点が`FCI`と異なります。なので`TTI`はJavaScriptの読み込みにより後ろ倒しになり、`FCI`は早々に要件を満たしたと評価される…というものですが、ネットワークコネクションの沈静化は2本以下になることが条件で、それはJavaScriptの読み込み時点で満たしているはずなのです。

もうひとつの仮説は、`TTI`がJavaScriptの実行開始を起点とするが(読み込み完了を待つか)、`FCI`はそうではない…というものです。

これも真相は掴めず仕舞いですが、またの機会に。

## JavaScriptを約2MBに重量化してhead要素に移動

レンダリングを初動でがっつりブロックして、JavaScriptとしての負荷も増大させるのでこれがおそらく最低スコアを出すだろう…と予想通りの結果に。

外部JavaScriptを(`async`や`defer`なしに)HTMLの上部に書くというのは枯れたアンチパターンのはずですが、それでも頻繁に見かけます。

この通り、PageSpeedスコアには甚大な影響があります。

## JavaScriptのロングタスク化

メインスレッドを500ms専有するロングタスクを100msおきに約20秒間、繰り返します。

表示系の評価は無傷ですが、JavaScript負荷系の`TTI`、`FCI`は狙い通り0点になりました。

ページ自体ではパフォーマンスに気をつけていても、ビジネス上必要な広告や解析系のサードパーティースクリプトがガンガンロングタスクを発生させるケースがかなり多いです。

ちょうどGoogleが重い広告をブロックする方向にあるというニュースがありましたが、

[「Chrome」、過剰に「重い」広告をブロックへ--8月から - CNET Japan](https://japan.cnet.com/article/35153802/)

各社サードパーティスクリプトもロングタスクを生じさせない品質を担保してほしいものです。