PageSpeed Insightsの採点ロジックについて詳しく調べてみたところ、意外なことがわかりました。
2020/6/3 追記
本家レポートよりPageSpeed Insightsのスコア改善が捗る裏レポートツールを公開しました。合わせてご参考ください。
https://simulate.site/cheatspeed-insights/
2020/3/19 追記
Lighthouse 6へのバージョンアップでこのページにかかれている内容が一部変更される可能性があります。
こちらも併せてご参考ください。
PageSpeed Insightsのスコア大変動か? Lighthouse 6 で変わる採点ルールを先取りチェック! - アイデアマンズブログ
点数に反映される監査項目は5つだけ
PageSpeed Insightsを実行するといろいろな指摘事項が出てきます。なので指摘が多いと点数が下がる減点方式と思われがちです(私もそう思っていました)。
実は、PageSpeed Insightsの点数はたった5つの監査スコアの加重平均で計算されています。
-
Interactive
インタラクティブになるまでの時間(重み 5) -
Speed Index
速度インデックス (重み 4) -
First Contentful Paint
コンテンツの初回ペイント (重み 3) -
First CPU Idle
CPUの初回アイドル (重み 2) -
First Meaningful Paint
意味のあるコンテンツの初回イベント (重み 1)
指摘項目はあくまで上記の指標を改善させるためのアドバイスです。指摘をクリアしても直接点数が上がるわけではありません。
逆にどんな手を使おうと上記の指標を改善すればPageSpeed Insightsの点数が上がります。技術的に頑張るよりコンテンツを見直す方が効率よく点数を上げられる場合が多いと思います。
PageSpeed Insightsで満点をとる方法
もうひとつ、100点を取るための具体的な条件を特定しました。
以下のすべて条件を満たせば、PageSpeed Insightsの点数が必ず100点になります(Lighthouse 4.3.0時点)。
-
Interactive
インタラクティブになるまでの時間1900ms以下
-
Speed Index
速度インデックス1950ms以下
-
First Contentful Paint
コンテンツの初回ペイント1350ms以下
-
First CPU Idle
CPUの初回アイドル1950ms以下
-
First Meaningful Paint
意味のあるコンテンツの初回イベント1350ms以下
3Gネットワーク相当の通信環境での条件なので容易ではありません。
採点ロジック
PageSpeed Insightsは内部でLighthouseを利用しています。
LighthouseはGoogle Chromeチームが主導するオープンソースのWebページ監査ツールです。Lighthouseのパフォーマンスカテゴリスコア = PageSpeed Insightsの点数
です。
Lighthouseのスコア計算を行っている部分を追ってみましょう。
カテゴリスコアは監査スコアの加重平均
パフォーマンススコア(PageSpeed Insightsの点数)のようなカテゴリスコアの計算を行っているのがscoring.jsです。
L75付近で監査項目のスコアscore
を、重みweight
を加味して加重平均しています。
const scores = auditRefs.map(auditRef => ({
score: resultsByAuditId[auditRef.id].score,
weight: auditRef.weight,
}));
const score = ReportScoring.arithmeticMean(scores);
監査項目は5つ以外 weight=0
加重平均なので重みweight
が0だと、その監査項目のスコアがどんなに高くても全体の点数にはまったく反映されません。
PageSpeed InsightsをAPI経由で実行するとJSONデータが得られます。上記の計算に使われているlighthouseResult.categories.performance.auditRefs
を見ると、weight
が0以外なのは5項目だけです。
"auditRefs": [
{
"id": "first-contentful-paint",
"weight": 3,
"group": "metrics"
},
{
"id": "first-meaningful-paint",
"weight": 1,
"group": "metrics"
},
{
"id": "speed-index",
"weight": 4,
"group": "metrics"
},
{
"id": "interactive",
"weight": 5,
"group": "metrics"
},
{
"id": "first-cpu-idle",
"weight": 2,
"group": "metrics"
},
{
"id": "estimated-input-latency",
"weight": 0,
"group": "metrics"
},
// ...略(以下のweightはすべて0)...
]
つまり、first-contentful-paint
、first-meaningful-paint
、speed-index
、interactive
、first-cpu-idle
以外の監査スコアはいくら改善してもそれ自体では全体の点数は上がらないということです。
監査項目ごとの点数はどう計算されているか
interactive
などの監査項目はいずれもタイミングに関する指標で、単位はミリ秒(ms)です(SpeedIndexは諸説ありますが、ここではms単位として扱われています)。
例えば重みが最も大きいinteractive
はinteractive.jsにおいてAudit.computeLogNormalScore
メソッドでスコアリングされています。
return {
score: Audit.computeLogNormalScore(
timeInMs,
context.options.scorePODR,
context.options.scoreMedian
),
rawValue: timeInMs,
displayValue: str_(i18n.UIStrings.seconds, {timeInMs}),
extendedInfo: {
value: extendedInfo,
},
};
Audit.computeLogNormalScore
を追っていくと、audit.jsや、statistics.jsで対数正規分布上のパーセンタイルでスコア計算をしているようです。
2019/4/24追記 難しくて執筆当時は端折ってしまいましたが、あとで調べたところ対数正規分布の分布関数が実装されていました。パフォーマンス指標は対数正規分布になるとみなし、累積分布関数である値が上位何%に位置するか(要は100人中の順位)求めます。1に対する補数がスコアになるという計算です。
逆算して満点を取る条件を見つけようとしたのですが断念…次のプログラムで50ms単位の閾値を探しました。それが冒頭の100点を取る条件です。
// yarn add lighthouse tsv
const Interactive = require('lighthouse/lighthouse-core/audits/metrics/interactive'),
SpeedIndex = require('lighthouse/lighthouse-core/audits/metrics/speed-index'),
FirstContentfulPaint = require('lighthouse/lighthouse-core/audits/metrics/first-contentful-paint'),
FirstCPUIdle = require('lighthouse/lighthouse-core/audits/metrics/first-cpu-idle'),
FirstMeaningfulPaint = require('lighthouse/lighthouse-core/audits/metrics/first-meaningful-paint'),
Audit = require('lighthouse/lighthouse-core/audits/audit'),
Tsv = require('tsv')
const classes = [Interactive, SpeedIndex, FirstContentfulPaint, FirstCPUIdle, FirstMeaningfulPaint]
const rows = []
for (let ms = 0; ms < 30000; ms += 50) {
const row = { ms }
for (let cls of classes) {
const opts = cls.defaultOptions
row[cls.name] = Audit.computeLogNormalScore(
ms,
opts.scorePODR,
opts.scoreMedian,
)
}
rows.push(row)
}
process.stdout.write(Tsv.stringify(rows))
300サイトのデータで検算
以前、通販上位300サイトについてPageSpeed Insightsを実行したデータがあります。
このデータで検算したところ、5項目のスコアの加重平均 = 全体の点数
で完全に一致しました。ここまでの説明で採点ロジックはほぼ間違いないと確認しました。
以上です。参考になれば幸いです。