ぱすたけ日記

日記っぽいのを書きます。

とりあえずシュッとパフォーマンスチューニングの目星を付ける

この記事ははてなエンジニアアドベントカレンダー2017の14日目*1であり、且つ後輩が徳島旅行に行っているので、日程がスワップされた結果KMC Advent Calendar 2017の14日目の記事でもあります*2

はてなエンジニアアドベントカレンダーの13日目の記事は id:amagitakayosi さんのインターネット溶かすボタンできた - マルシテイアでした。KMCアドベントカレンダーの13日目の記事は id:opesan くんの 聖地巡礼記2017 - おぺの日記でした。

さて、今年2017年は素晴らしい年で、フロントエンドのパフォーマンスチューニングに関する良い書籍が2冊も出ました。

Webフロントエンド ハイパフォーマンス チューニング

Webフロントエンド ハイパフォーマンス チューニング

超速!  Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

「目星をつける」のゴール

フロントエンドのパフォーマンスチューニングに関する具体的なテクニックは上記の書籍などに譲るとして、この記事ではそもそもフロントエンドのパフォーマンスチューニングをやる必要があるのか、取り組むとしたら何に手をつけると良さそうなのかということに、ひとまず 大雑把に目星を付ける という話をします。具体的には、ひとまず15分くらい取り組んでみて、以下の点についてざっとチーム内などで共有できることを目指します。

  • フロントエンドのパフォーマンスチューニングが必要かどうかを判断する
  • パフォーマンスチューニングで取り組むと良さそうな箇所を把握する
    • 可能ならばパフォーマンスの問題を起こしている原因の概要も把握する

(Mac上のChrome v63 の Developer Tools を用いた操作や画面の説明を掲載しています。他のOSやブラウザ、Chromeのバージョンの違いに依って異なる場合があります)

フロントエンドのパフォーマンスチューニングが必要かどうか

まず、そもそもボトルネックがフロントエンドの実装、特にJavaScriptの層にあるのかどうか判断することが必要です。例えば、APIサーバーのレスポンスが遅い場合などはそちらを対処すべきですし、レンダリングが遅いのは画像の配信が遅いことに引っ張られている可能性もあります。Devloper ToolのNetworkタブでそれらに関するヒントを得ることができます。

Networkタブを開いた状態であるページをロードしたときの結果の一部を挙げます。

Networkタブの結果の棒グラフは色々な情報がある*3のですが、ここではざっくりと以下の2点を観察することにします。

  • 緑: サーバにリクエストしてから1byte目を受け取るまでの時間
  • 青: そのレスポンスをダウンロードするのにかかった時間

これを念頭に置いて先ほどのグラフを見ると、画面中央の辺りでいくつかの緑のグラフが4000msec〜6000msec分あることが分かります。 緑はサーバからのレスポンスが到達し始めるまでの時間なので、これらのエンドポイントはサーバサイドでAPIレスポンスを生成するまでに問題がありそうなことが分かります。この部分に関してはフロントエンドよりもまずはAPIの設計や実装を見直すと良さそうです。

詳細な時間やAPIのレスポンス内容について知りたい場合、name部分をクリックすることでレスポンスのヘッダーや時間の詳細を見ることが出来ます。

Performanceタブを眺める

Networkタブでウェブアプリケーションの通信に関する部分を観察したので、次に本丸のフロントエンドのパフォーマンスについて観察していきたいと思います。

ChromeのDeveloper ToolにはPerformanceというタブがある*4ので、今回はそれを観察します。Macの場合、Command + Shift + Eでリロード→集計開始をやってくれます。

グラフを眺めて概観をつかむ

先ほどNetworkタブで素振りをしたのと同様に次の2色について着目してひとまず観察することにします。

  • 紫: ブラウザのレンダリングに関する時間
  • 橙: JavaScriptの実行に関する時間

というわけで、あるウェブサイトで集計した例を提示します。

橙もなんとかしたいのですが、今回は特徴的な中央右寄りの紫の部分を今回は観察することにします。紫の部分はレンダリングに関する部分で、要素のwidth/height/left/topなどを取り扱うフェイズです。特にこの紫の部分がボトルネックになっている場合、強制同期レイアウト(Forced Synchronous Layout)*5が発生している可能性が考えられます。

この強制同期レイアウトが頻出してFPSが下がっている場合、次のような橙と紫の関係性のグラフになっていることが多いので、このようなときは注意が必要です。

from https://developers.google.com/web/tools/chrome-devtools/rendering-tools/forced-synchronous-layouts

箇所を特定する

では、前述のグラフから怪しそうな紫色が大半を占める部分を拡大して見てみることで何が原因になっているか探ってみます。

(文字が隠れていて見えませんが)Recalculated StyleとLayoutに時間がかかっていることが分かります。紫のバーの右上に赤い三角があるのは強制同期レイアウトが起きている印なので、これによってScriptの実行がブロックされていることが分かります。さらにそれらの出来事は whenXS という名前の関数内で発生していることが分かります。

この強制同期レイアウトの原因を取り除く*6と次のような状態になって、ここから先はXHRのReadyStateChangeのあとに起きていることなどをつぶさに観察してJSのロジックなどを改善していけば良さそうという方針が立てられそうです。

Performanceタブではその他にもJSのヒープやCPUの使用量についても観察できるので適宜参考にすると良さそうです。またレンダリングやアニメーションについて深く追いたい場合はDeveloper ToolのMoreToolからLayersタブを開いたりすると良い情報が得られるかもしれませんし、JavaScriptの実行について詳しく追いたい場合は同じ場所から開くことが出来るJavaScript Profilerなどを使うと良いでしょう。

最後に

フロントエンドのパフォーマンスチューニングに問題がありそうな時に、ひとまずシュッとウェブサイトの状態を観察してボトルネックらしき箇所を特定するときに僕が取り組んでいるアプローチについて紹介しました。

また、フロントエンドのパフォーマンスチューニングに関する代表的なテクニックや基本的な向き合い方などは過去の発表資料で紹介しているので、良ければそちらも御覧ください。

参考

*1:9月末からはてなでマンガビューワーのフロントエンドをやるアルバイトをしています

*2:本当は別々の記事を書こうと思っていたのですが、許してください

*3:https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#timing-explanation

*4:詳細は https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/

*5:https://developers.google.com/web/tools/chrome-devtools/rendering-tools/forced-synchronous-layouts

*6:詳細は省きますが、強制同期レイアウトを呼び起こす関数の利用をとにかく回避する