レイアウトランのパフォーマンス最適化
こんにちは、ゼノフィseoです。
Ext JS アプリケーションにパフォーマンスの問題が出始めた場合、開発者が疑うべき点は大抵いくつかに絞られます。大きくは、ネットワークの限界(帯域とレイテンシー)、端末のメモリー/ストレージの限界、レイアウト/レンダリング問題に分けられます。本記事ではExt JS クラシックツールキットアプリケーションのレイアウト/レンダリングプロセス(レイアウトラン)を最適化することのみに焦点を当てます。レイアウト/レンダリング問題は、ひとつのコンテナビューが何十ものコンポーネントを抱えるほどアプリケーションが大きくなった場合に概して発生し、ここで不必要なレイアウトランを引き起こします。
レイアウトランを理解する
Ext JS のコンテナクラスが初期化される際、コンテナビューを構成する全てのコンポーネントを初期化し結びつけるプロセスが開始されます。コンテナおよびそのコンポーネントのレンダリング/レイアウトパフォーマンスを最適化するにあたり、DOMに要素を追加したり、除外、変更する都度発生するCSS/スタイルやレンダリングの計算を回避することが目標となります。ブラウザはこれらのスタイル計算をキャッシュしますが、新しいコンポーネントがコンテナに追加されたり、除外、変更される都度、スタイル値は再計算が必要になります。これがExt JS 6 が各コンポーネントを別々にではなく、バルクでレンダリングする理由です。バルクレンダリングは全体のコンポーネントツリーをHTMLで作成し、それをDOMに一気に書きます。レンダリング後、Ext JS はレイアウトランというプロセスを開始します。ここでビューポートのコンポーネントに対してレイアウトのサイズや位置、およびスタイルの値を計算します。autoやflex、およびその他動的な値を使用するコンポーネントのレイアウト/スタイル値は不明であるため、その他のコンポーネントの値を基に計算する必要があります。パフォーマンスを改善するためには、再計算や不具合につながる不必要なレイアウトランを最小限に抑える必要があります。
レイアウトランを検出する
不要なレイアウトランを除外するためにまずは、それらを見つける必要があります。2つの簡単な方法でレイアウトランを検出することができます。まず、Sencha Inspector はそれを確認する機能を備えています。Sencha Inspector の三つめのタブは開発者がレイアウトランを確認するためのものです。Watchボタンをクリックするだけで監視を始めることができます。新しいレイアウトランが引き起こされると、それに影響を受けたコンポーネントのリストと共に一覧に表示されます。
二つめの方法では、次のコードをGoogle Chrome Consoleにコピー&ペーストすることでレイアウトランを検出します
Ext.Function.interceptBefore(Ext.layout.Context.prototype, 'run', function () { console.log('Layout run'); debugger; }) |
このコードはレイアウトランへのコールを捕捉し、デバッガキーワードへコールすることでブレイクポイントを引き起こします。デバッガキーワードはブレイクポイントを設定することと同等であるため、コードの実行は一時停止されます。これにより開発者はコールスタックを調べ、どのメソッドがレイアウトランを引き起こしたかを見極めることができます。図2ではレイアウトランを捕捉するコードの行がデバッガに設定されている例を示しています。タブパネルの新規タブがアクティベートされると、コンソールログが”レイアウトラン”を出力し、ブレイクポイントが引き起こされます。レイアウトランを引き起こしたイベントを調べるためにコールスタックがトレースされます。この場合、タブパネルのアクティブイベントにより引き起こされたレイアウトランは一つだけでした。
レイアウトパフォーマンスを最適化する
あるひとつのアクションやイベントがいくつかのレイアウトランを引き起こしていることを検出した場合、それを最適化できる可能性はあるでしょう。かなりの頻度でこれは、コンテナビューがレンダリングされた後に複数のコンポーネントをそれぞれ追加する処理を行っている場合に発生しています。新しいコンポーネントをコンテナビューに追加する都度、新しいレイアウトランが引き起こされます。複数のコンポーネントを追加する必要がある場合は、Ext.suspendLayouts()メソッドをコールすることでレイアウトランを保留することができます。追加、または変更したい全てのコンポーネントがコンテナビューに追加、または変更されれば、そこでExt.resumeLayouts(true)メソッドを通してレイアウトランを再開すれば良いのです。
もしあるイベントが新しいレイアウトランを引き起こした場合、変更されたコンポーネントのコンテナのサイズ(幅や高さ)に静的な値を設定することでパフォーマンスを更に調節することができます。これによりコンポーネントの変更が、隣接するコンテナやそのサイズ、レイアウトにどのように影響するかを考慮すること必要がなくなり、変更による影響を軽減することができます。
Sencha Inspector はExt JS トライアルの一部として無料で入手できます。Sencha Inspector について詳細 (英語)はこちらに記載しています。
これらのパフォーマンス改善を試していただき、そこで気づいた点などを以下のコメント欄で共有してください。
私はベルギーのJSConfや今後のSenchaイベントに参加する予定です。お立ち寄りいただき、あなたのExt JS アプリのパフォーマンスについてお話しできればと思います。