【Deprecated】フロントエンドパフォーマンス分析 はじめの一歩

**【Deprecated】**新しく [Web パフォーマンス分析の概観](https://qiita.com/phanect/items/c6db61456435ad303742)という記事を書き直しました。


Webパフォーマンス Advent Calendar 2017 8日目です。

私がフロントエンドのパフォーマンスを始めて4ヶ月程経ちました。
フロントエンドにおけるパフォーマンス分析を行うにあたり、学んでおくべきことの概要としての記事を書いておきたいと思います。

尚、フロントエンドとは言うものの、どちらかというと「フロントエンドからわかること」を分析する、という方向性なので、改善策自体はバックエンドやインフラストラクチャーの部分になる場合もあります。

分析と計測の方法
==============

ウォーターフォールチャート
----------------------

ウォーターフォールチャートというのは、Chrome DevTools の Network タブにあるアレです。開発手法のアレとは特に関係ありません。

![Chrome DevTools のウォーターフォールチャート](https://qiita-image-store.s3.amazonaws.com/0/41297/3937fc10-88d2-5002-ef59-572ae2803e0c.png)

ウォーターフォールチャートを確認することで、どのファイルのダウンロードにどの程度時間がかかっているのか確認することができます。
これは基本的にリクエストを送る前から、ダウンロード完了までについて調査する際に必要となる図です。

読み方については、[Google のドキュメント](https://developers.google.com/web/tools/chrome-devtools/network-performance/resource-loading)が参考になります。
また、それぞれの色の部分が何を示すかについては少し理解しづらいので、[Resource Timing について](https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing)も読んでおくと良いでしょう。

最初の HTML のダウンロードに時間がかかっていれば、バックエンド又はインフラが重い。画像等静的コンテンツのダウンロードに時間がかかっている場合は、ファイルサイズが極端に重いわけでない場合、インフラが重い…など、色々わかることがあります。
JavaScript が早い段階で読み込まれ過ぎている場合、[defer や async を使っても良いかもしれません。](https://qiita.com/phanect/items/82c85ea4b8f9c373d684)

また、[WebPageTest.org](https://www.webpagetest.org) でもウォーターフォールチャートはサポートされています。

![Screenshot_20171205_112308.png](https://qiita-image-store.s3.amazonaws.com/0/41297/b1b504d8-490f-c6a5-626b-40583fdea4a2.png)

こちらでは、読み込む物理的な場所 (東京、香港、ロンドン、等) や、回線 (光、LTE、等) も指定できますので、比較的実際のユーザーの環境に近い環境で実施できます。
モバイルサイトの速度のテストを、オフィスの光回線でやっても、実際の LTE 回線の速度より高速な結果が出るでしょうし、グローバルサイトの速度のテストを東京だけでやっても意味がありません。(例えば東京にしかサーバーがなければ、当然ロンドンでは非常に重くなります。)

ランタイムパフォーマンス
---------------------

Chrome DevTools の Performance タブで、JavaScript など、フロントエンド側の処理について分析します。どの JavaScript ファイルで、どの程度処理に時間がかかっているか、などがわかります。

![Chrome DevTools のパフォーマンスタブ](https://qiita-image-store.s3.amazonaws.com/0/41297/0ed07557-eb69-7344-d949-d829c1621f5f.png)

フィルムストリップ
---------------

下記の画像のように、何ミリ秒の時点で、ページがどれだけ表示されているかを確認するためのスクリーンショット群です。First Paint などのタイミングを測る時に重要になります。

![フィルムストリップ](https://qiita-image-store.s3.amazonaws.com/0/41297/9bcb1ec2-c049-9344-bab9-c0db91d1538e.png)

[Chrome DevTools のネットワークタブで、カメラマークを押すと取得できます。](https://developers.google.com/web/tools/chrome-devtools/network-performance/resource-loading#filmstrip)

Synthetic monitoring
--------------------

[Catchpoint](http://www.catchpoint.com) などのツールで、パフォーマンスの監視を行うことができます。
今のところ無償のサービスは聞いたことがありませんので、「はじめの一歩」としてはちょっと微妙かもしれませんが。

基本機能としては、WebPageTest.org と同じような機能を備えているのですが、その他に、下記のグラフのように、表示などの速度の推移を監視することができます。

![表示速度のグラフ (Catchpoint)](https://qiita-image-store.s3.amazonaws.com/0/41297/86e5b782-5c1b-03e2-c7fd-cb7ee0a09d70.png)

例えば娯楽系のサービスでは、一般に夜にアクセスが集中し重くなりますから、日中の業務時間中には、夜よりも高速な結果が得られますので、あまり参考になりません。
常にパフォーマンスを監視することで、重くなっている時間がないか、把握することができます。

サービスによっては、AWS の回線での計測だけではなく、実際のユーザーが用いる回線 (OCN の光とか docomo LTE とか) での計測結果を示してくれるものもあります。

RUM - Real User Monitoring
--------------------------

ページに JavaScript を埋め込み、ユーザーがページを閲覧した際の表示速度を取得してきます。

これも Catchpoint などのツールに機能があります。オープンソースでは、HubSpot が作っている [Bucky](http://github.hubspot.com/bucky/) というものがありました。

JavaScript の計測系 API
----------------------

[Navigation Time API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API) など、JavaScript で DOMContentLoaded や load などの時間を取得できる API があります。
Real User Monitoring と同様のことを、自分で実装することもできます。

大体はツールでも取得することができますので、私は今のところ頻繁には使いませんが、存在だけは頭の片隅に置いておくと良いと思います。


2. 分析の指標
============

パフォーマンス分析の際に注目すべき指標がいくつかあります。

DOMContentLoaded, Load までの時間
--------------------------------

HTML のパースが完了したタイミングを [`DOMContentLoaded`](https://developer.mozilla.org/ja/docs/Web/Reference/Events/DOMContentLoaded)、全ての画像・CSS・JavaScript のダウンロードと実行が完了したタイミングを [`load`](https://developer.mozilla.org/ja/docs/Web/Reference/Events/load) と呼びます。

`DOMContentLoaded` 及び `load` のタイミングの速さが、速度のひとつの指標になります。
以前程は重要視されなくなっている指標のようですが、基本として理解しておくべきだと思います。

First Paint 等までの時間
----------------------

こちらが最近主に注目されている指標のようです。下記のように、どの程度まで読み込まれたかを示すタイミングの名前として、

- Navigation Start
- First Paint
- First Contentful Paint
- First Meaningful Paint
- Visually Ready
- Time to Interactive
- Fully Loaded (≒ load)

という指標があります。
古川洋介さんのスライドがわかりやすいので、引用します。

![First Paint などの指標](https://qiita-image-store.s3.amazonaws.com/0/41297/daff9138-5520-efde-c52d-c5a84b9cc98a.jpeg)
出典: [You need to know SSR - Yosuke Furukawa](https://speakerdeck.com/yosuke_furukawa/you-need-to-know-ssr?slide=16)

[First Paint や First Contentful Paint は Navigation API で取得可能](https://developer.mozilla.org/en-US/docs/Web/API/PerformancePaintTiming)ですので、明確な数値として取得することが可能です。First Meaningful Paint は今のところできません。


Speed Index
-----------

こちらも最近重要な指標のようです。
どれだけの速度で、どれだけの面積が描画されているか、という考え方で計算される指標です。
計算式に積分の記号が出てくるなど、算出の仕方は少々複雑なようです…

参考: [Speed IndexというWebパフォーマンスの指標](https://1000ch.net/posts/2017/speedindex-for-web-performance.html)

その他
======

`async` と `defer`
------------------

JavaScript を読み込む際、そのまま `<script src="/path/to/code.js">` などと書くと、JavaScript のダウンロードや実行が、HTML の DOM 構築をブロックしてしまいます。
`defer` や `async` などの属性を用いることで、ダウンロードを HTML の DOM 構築と並列に実行したり、実行を遅らせたりできます。

詳細は以前 [\<script\> タグに async / defer を付けた場合のタイミング](https://qiita.com/phanect/items/82c85ea4b8f9c373d684) という記事に書いたので、こちらを参照して下さい。

Critical Rendering Path
------------------------

Critical Rendering Path とは、HTML や、そこに紐付いている画像・CSS・スクリプトなどのダウンロードから、First Paint までに、ブラウザー内部で行われる処理のことを言います。

具体的には、HTML や CSS の構文解析、DOM や CSSOM の構築や、どの位置にどのオブジェクトが描画されるべきかの座標計算などが行われます。

つまり、`<script>` タグを何度も追加したり、CSS のプロパティを JavaScript で頻繁に変更したりすると、このクリティカルレンダリングパスが何度も実行されて重くなります。

少し長いですが、[Google Web Fundamentals に9ページほどの資料](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/)があります。
もう少し短いものが良ければ、[以前私が訳した Catchpoint Systems の記事](https://spelldata.co.jp/blog/blog-2017-09-15.html)もありますので、こちらもよろしければどうぞ。

RAIL モデル
-----------

RAIL とは、

- Response
- Animation
- Idle
- Load

の略です。

フロントエンドにおいて、これらの処理にかかる時間は何秒以内であるべきか、ということを示したモデルで、Google が提唱しているようです。

それぞれ、

- Response - ユーザーの入力から**100ms**以内にレスポンスを返す
- Animation - 1フレームあたりで JS コードによる処理が**10ms**以内
- Idle - アイドル時間に実行される処理は**50ms**以内の処理に小分けする
- Load - ページの読み込みは**1s**以内

と決まっています。

本家 Google の[RAIL モデルでパフォーマンスを計測する](https://developers.google.com/web/fundamentals/performance/rail)や、
@ahomu さんの[RAIL という Web パフォーマンスモデルの概要](https://havelog.ayumusato.com/develop/performance/e664-rail_performance_model.html)が参考になるでしょう。