読者です 読者をやめる 読者になる 読者になる

kitak.blog

朝が早いエンジニアのブログ

Chrome DevTools の「Enable paint flashing」を使う

Frontend Browser

Chrome DevToolsに「Enable paint flashing」という機能があって、画面で描画が行われた箇所をハイライト表示してくれます。

DevTools を立ち上げて、下のペインの「Rendering」タブを選択するとあります。下にペインがない場合、右上の「︙」から「Show console」を選ぶとペインが表示されるはずです。

f:id:kitak:20151101124447p:plain

「Enable paint flashing」は、少し前まで「Show paint rectangles」という名前だったし、今後ひょっとしたらまた名前が変わるかもしれません。名前だけでなく、DevToolsのUIはChromeのバージョンアップによって変わっていくので、上の説明はあくまで参考程度にしてください。

描画が行われた箇所がハイライトされて、なにがうれしいのかというと、不要な描画を除くことで、ブラウザのレンダリング処理が改善されて、使いごこちのよいUIをユーザーに提供できるということです※。

ブラウザがレンダリングの1フレームでおこなう処理は、ざっくり「Loading」「Scripting」「Rendering」「Painting」に分けられますが、極端な事例を除けば、「Painting」のコストが相対的に高いと言われています。 ブラウザは、ユーザが操作するたびに画面全てを描画するのではなく、必要な箇所のみ描画するよう、よしなにやってくれていますが、JavaScriptスタイルシートの記述によっては本来不要な描画が走ります。

いくつか不要な描画とその改善の例を紹介します。

例えば、スクロールによって追従するヘッダーやメニュー。「Enable paint flashing」を有効にして、スクロールをしたときにずっと緑色でハイライトされる箇所があれば、改善のサインです。

GPU合成を行うようにJavaScriptスタイルシートの記述を変更します( GPU合成によるスムーズなアニメーションについては、プリンより滑らか。スムーズなアニメーションの作り方 プリンより滑らか。スムーズなアニメーションの作り方。 - HTML5 Conference - - YouTube が分かりやすいです )。GPU合成が行われるようになれば、(将来的に色が変わるかもしれないですが)これまで緑色でハイライトされていた箇所がハイライトされないようになります。あるいは「Show layer borders」を有効にして、これまで緑色でハイライトされていた箇所が橙色の枠で囲まれていることを確認します。

スクロールに追従するUIに限らず、スライドショーやスライダーのようなUIのアニメーションもGPU合成が行われているかチェックする価値があります。
また、ライブラリを選定するときの基準としても有用でしょう。ライブラリのデモページで操作に伴って緑色のハイライトが目立つ場合は「うーん... 微妙」というかんじです。

次にリスト操作。リストにアイテムを追加したり、削除したり、といったことはよくあると思いますが、実装するときは、操作のたびにリスト全体が描画の対象にならないようにすることがひとつのポイントになります。リストに追加したり、削除するたびにリスト全体がちらつくUIはお世辞にも立派とは言えません。「Enable paint flashing」を有効にすることで、リスト全体で描画がおこなわれていないかどうかの視認が容易になります。

数年前までは、DOM職人によるリストの効率のよいDOM操作がおこなわれていましたが、 最近はAngular.js, Vue.jsのような双方向データバインディング、React, MithrilのようなVirtualDOMの概念を持つフレームワーク・ライブラリが広く使われるようになってきています。
これらは概念、表面的なAPIは異なっていることもありますが、DOM操作をフレームワーク・ライブラリに委ねる、という点は共通です(どの程度委ねるかは違いますが)。
リスト操作のようなどのアプリケーションでも登場するUIロジックはフレームワーク・ライブラリでよしなにやってくれるので、昔よりは温かみのあるDOM操作は不要になってきています。
とはいえ、完璧に任せてもよいかというとそうでもなく、これらのフレームワーク・ライブラリを使ったことのある人は知っていると思いますが、idやkeyのようなリストアイテムを一意に識別できるものを割り振る必要があります。これはフレームワーク・ライブラリが効率のよいリスト操作を実現するために必要なヒントです。これがないと操作のたびにリスト全体で描画が行われることもあるので、ただ適当にフレームワークやライブラリを使えば良い感じになるというわけでもありません。

最後に双方向データバインディングに関連した話。
Angular.jsやVue.jsのようなフレームワークを使っていると、双方向データバインディングのチェインによって、ある値の変更が意図していない場所に伝播し、不要な再描画が発生することがあることかもしれません。この場合、「Enable paint flashing」を有効にして、操作することで不要な描画が行われている箇所を特定することができます。 こういった場合は、コンポーネントの設計やデータバインディングの範囲を見なおすといいかもしれません。

いくつか不要な描画とその改善の例を紹介してきました。 極端に神経質になる必要はないと思いますが、一通りコーディングを終えた後に触ってみて、表示や操作がカクつく違和感を感じたり、モバイル向けのウェブサイト・アプリケーションを開発していて可能な限りパフォーマンスを向上したい、という場合は不要な描画をみつけてレンダリングの改善を図ってみたらどうでしょうか。

※ PaintingではなくLoading, Scripting, Renderingにボトルネックがあるケースもあるし、その場合はTimelineやProfilesで原因を特定して改善を図ります。