Chrome DevToolsを使ったフロントエンドパフォーマンス改善

はじめまして、「SEARCH WRITE」開発チームで主にフロントエンドを担当している坂井です。PLAN-Bに2022年4月に中途入社して1年が経ちました。

フロントエンドのパフォーマンスを向上させることは、ユーザー体験の向上において非常に重要です。
以前、 同じSEARCH WRITE開発チームの山口もフロントエンドパフォーマンス改善の事例を紹介しました。


本記事ではChrome DevToolsのPerformanceパネルを使って実際のプロダクト開発で行ったパフォーマンス計測と改善の記録をまとめました。

パフォーマンス改善の対象

SEARCH WRITEはVue.jsで作られたSPAで、バックエンドとのデータのやり取りはVue.jsを介して行います。

今回のパフォーマンス改善の対象ページでは、Web APIから受け取ったデータをもとにリストを表示しています。

対象ページのリスト

データの表示件数は、ある値をしきい値として制限していましたが、そのしきい値を解除してほしいとの要望がありました。
そのしきい値はバックエンド側で制御しているもので、フロントエンド側で特にコードの変更は必要ありませんでした。しかし、データによってはしきい値で制限していたときは200個だったデータ数が、しきい値を解除することにより1,000個程度に増加することがわかりました。
データ数が増加することで画面が重くなる可能性があると考え、フロントエンド側でもパフォーマンスの計測を行うことにしました。

実際に軽く画面で動作確認をしてみると、データ表示時と他の画面に切り替える際に、体感でもわかるほど表示・切り替えに時間がかかっていることがわかりました。

Chrome DevToolsのPerformanceパネルを見てわかったこと

体感的に遅くなることもわかったところで実際にツールを使ってパフォーマンスの計測を行い、ボトルネックを見つけることにしました。

どの文脈においてもですが、パフォーマンスを向上させる上で重要なのが、ボトルネックを推測せずに正しく現状を計測することです。

今回はGoogle ChromeのDevToolsに標準機能として搭載されているPerformanceパネルを使って計測しました。

Performanceパネルは、ウェブページのパフォーマンスを分析するためのツールです。ページの読み込み速度やスクリプトの実行速度、レンダリング速度などを計測し、パフォーマンスのボトルネックを特定することができます。
なお、Lighthouseパネルで計測する方法もありますが、今回のページはページ内タブで切り替えてデータの表示を行うという性質上、使うのが困難だったため使用していません。前述の記事ではLighthouseで実際に計測したものが掲載されていますのでご参考にしてください。

計測環境は以下の通りです。

  • MacBook Pro 14インチ
  • CPU:Apple M1 Pro
  • メモリ:32GB
  • OSバージョン:macOS Ventura 13.1

Chromeのバージョンは112.0.5615.121を使用しました。

PerformanceパネルではCPUのスロットリングを設定することができ、ユーザーのマシンスペックに近い状況を再現するために今回は6x slowdownに設定しました。また、今回使用したデータ数は714件となっています。

改善前のパフォーマンス検証画像

計測の結果、該当画面に切り替えたときで3,439ms、該当画面から切り替えたときで2,697msかかっており、いずれの場合もLong Taskとなっていました。
※Long Taskとは、完了するまでに50ms以上かかるタスクのことです。

Bottom-UpやCall Treeなどを使うとJavaScriptやレンダリングなど、どの処理に時間がかかっているか詳細にわかります。
実際に調査していくとVue.jsのコンポーネントのmountとdestroyに多くの時間がかかっていることがわかりました。実装上、リストの行単位でコンポーネント化がされており、そのコンポーネントの1個のmountに1ms以上かかっている場合も多くありました。714行分のコンポーネントをmountするとなると多くの時間がかかってしまいます。

パフォーマンス改善のために行ったこと

一度にmount、destroyするコンポーネント数を減らせば結果的にパフォーマンスが上がると考え、バーチャルリストの導入を試しました。

バーチャルリストは、大量のデータを効率的に表示するための技術です。バーチャルリストは、表示される要素を限定し、スクロール時に適宜表示・非表示を切り替えることで、パフォーマンスを向上させることができます。見えていない範囲の要素はレンダリングしない=コンポーネントがmountされないため、データの件数が増えても、mountされるコンポーネントの数は変わらず、パフォーマンスが低下しないというメリットがあります。

SEARCH WRITEではすでに他のページでバーチャルリストが使用されており、比較的導入は容易でした。とは言っても、バーチャルリストの導入によりDOM構造が変更になったため一部CSSの変更も生じ合計で3日程度かかりました。

パフォーマンス改善の結果

バーチャルリストを導入した状態でもう一度パフォーマンス計測を行いました。

改善後のパフォーマンス検証画像

計測の結果、該当画面に切り替えたときで429ms、該当画面から切り替えたときにも129msとまだLong Task状態ではありましたが改善前に比べて1/8〜1/20程度の速度で画面切り替えが行えるようになり、パフォーマンスが改善しました。
この状態でリリースができると判断し、リリースを行いました。

まとめ

僕自身はこれまでパフォーマンスを計測するときにLighthouseを最初に選択していました。
今回のようにページ内タブで実装されており、ページ読み込み時に計測対象が画面表示されず、Lighthouseが使えないような状況では、Performanceパネルを使うことが有用であることがわかりました。

バーチャルリストが導入済みでもパフォーマンスが悪いページがあります。
今回のように、Chrome DevToolsのPerformanceパネルなどを利用して、パフォーマンスの改善を行っていき、ユーザーに快適に使ってもらえるように努めていきます。

Appendix

今回は特に実施しませんでしたが、Vue.jsのパフォーマンス悪化の原因を調査してわかったことに以下のようなものがあります。

  • v-onceを利用する。v-onceは要素やコンポーネントを一度だけレンダリングし、再描画を行わないようにできます。今回のケースでは利用できませんでした。
  • 子コンポーネントでの処理を親コンポーネントに移す。処理を親コンポーネントに移し、子コンポーネントでは処理を行わず表示のみに専念させ、データの受け渡しや処理のオーバーヘッドを少なくすることでパフォーマンス改善が期待できます。今回のリストの行のコンポーネントでは多くの処理が行われており、この方法でも改善がある程度期待できました。しかし、今回の対象はリスト表示のため、処理を移すよりバーチャルリストを導入するほうが効果は高いと考え、この方法を試しませんでした。