Angularアプリの中でもng-repeatはパフォーマンスのボトルネックとなりやすいことで有名です。
リストを活用する場合にはtrack byやOne-time bindingsを利用するのが標準となっています。
しかしこれら両方を利用しようとすると予期しない結果を招くこともあります。
この記事ではng-repeatの利用例を見ながらスピードアップを図る改善策を紹介していきます。
リスト全体をリフレッシュする
シナリオ:
ng-repeatでレンダリングを行うリストは、1行ごとに編集や変更を施すことができません。
しかしブラウザの更新ボタンでリロードされた場合にはリストがサーバーから再びダウンロードされ、現在表示されているリストを置き換えます。
このようにリスト全体を表示し直す動作は遅く感じられ、ブラウザが少しフリーズするように見えてしまいます。
改善策:track by
track byを使ってみましょう。
このシナリオでは、リストが変更されるとAngularがng-repeat内の全てのDOMエレメントを破棄し、新しいものを作成します。
リストのほとんどの部分が変更されていなくても同様です。
リストが大きい場合にはラグも大きくなります。
track byを利用することで、Angularはng-repeat内のエレメントをどう再利用すればいいのか把握することができます。
DOMの操作を減らすことはラグを小さくすることにつながります。
編集可能なコンテンツ
シナリオ:
ユーザーが変更可能なリストや表を表示する場面があるでしょう。
編集可能なフィールドがあったり、ダイナミックなウィジェットとともに利用されるセルがあったりもします。
ここでデータ内に起こった変更を把握できないとリストの変更箇所が表示されないという問題が発生することがあります。
改善策:イミュータブルオブジェクトとOne-time bindingsの利用
リスト内にあるひとつのオブジェクトが変更された場合、Angularはその部分のDOMエレメントを作成し直すことはありません。
そのためOne-time bindingsはアップデートされることがないのです。
これは不便ですが、より現代的なデータフローとイミュータブルオブジェクトを活用するいい機会とも言えます。
次のコードではオブジェクトに変更を施しています。
このように変更するかわりに、モデルをイミュータブルなものとして扱いましょう。
変更が必要な場合にはデータのクローンを作成しモデルオブジェクトを置き換えるのです。
まとめ
ng-repeatは問題になることも多いですが、うまく使いこなすことも不可能ではありません。
これらの例を参考に、アプリの高速化に役立ててください。
※本稿は「Techniques for Improving ng-repeat Performance」を翻訳・再編集したものです。