ページグリッド(2つのネストされたng-repeat)を備えたAngularJSアプリがあります。 1ページには約25x40の入力要素があります。 1000バインディングを作成した当初は、ページングパフォーマンスは許容範囲でした。
しかし、ページの複雑さが増します:動的クラス、さまざまなコンテキストメニュー、グリッドの各セルの条件付きコンテンツ。また、推定6000バインディング(入力要素ごとに6)で、ページングが遅くなり、使用できなくなりました。
私の質問は、AngularJSのパフォーマンスの問題に一般的にどのように対処するかです。明らかに最初のステップは測定することです。しかし、Chromeプロファイラーの結果は、続行方法を知ることからほど遠く、私にそれほど多くを教えません。
Self Total Function
-----------------------------------------------------------------
24 ms 2.79 s angular.js:7997 Scope.$digest
1 ms 1 ms controllers.js:365 setViewportData
16 ms 692 ms angular.js:13968 ngRepeatWatch
8 ms 22 ms angular.js:6439 extend.literal
9 ms 1.22 s angular.js:14268 ngSwitchWatchAction
16 ms 45 ms angular.js:12436 ngModelWatch
0 621 ms angular-ui-4.0.js:264 initDateWidget
0 13 ms angular.js:12859 ngClassWatchAction
0 70 ms angular.js:14184 ngStyleWatchAction
1 ms 5 ms angular-ui-4.0.js:261 getOptions
0 16 ms angular.js:579 copy
0 1 ms angular.js:4558 interpolateFnWatchAction
1 ms 2 ms angular.js:5981 token.fn.extend.assign
0 37 ms angular.js:8151 Scope.$eval
1 ms 1 ms angular.js:6137 extend.constant
14 ms 16 ms angular.js:651 equals
1 ms 1 ms angular.js:4939 $interpolate.fn
余談ですが、「Object.observe()」が将来的に高速化する可能性はありますか(「initDateWidget」を無視すると、明らかに別のトピックになります)?
Angularアプリを最も高速化するためにできることは、できる限りバインディングを減らすことです。これを行う1つの方法は、テーブルを作成するディレクティブを作成することですng-repeatsを使用する代わりにDOM操作を使用して、これにより、処理する必要のある全体的なウォッチの数が減少し、$ digestが大幅に高速化されます。
これを行うのは醜いことはわかっていますが、Angularは実際には3000以上のバインディングをセットアップすることを意図していません。ダイジェストを実行し、オブザーバーパターンではないため、多くの設定を行うと、処理速度が実際に低下します。
Ng-repeatを引き続き使用するハイブリッドアプローチを実行することもできますが、すべての値はカスタムディレクティブからの直接DOM操作でDOMに配置されるため、すべてのバインディングが回避されます。
まだ行っていない場合は、AngularJS Chromeプラグイン、Batarangをインストールしてください。これにより、どのバインディングが問題の原因となっているかを特定するのに役立ちます。 https://chrome.google .com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl = ja
他の答えが示唆しているように、探しているのは、バインドするモデルが画面に表示しているサブセットである、テーブルの無限スクロール設定の小さなケースです。
Ng-gridコンポーネントはこれを実装しており、直接使用するか、手法を盗むかを検討する価値があります。 http://angular-ui.github.com/ng-grid/
大きなリストでのangularJSのパフォーマンスに関するこの投稿 には、パフォーマンスのチューニングに使用できるオプションの概要があります。
上記の回答(Batarangプラグインを除く)も記載されています。これは、その記事のヒントの概要にすぎません。
より明白な解決策の1つは、ビュー内のアイテムの数を減らすことによってバインディングの量を減らすことです。データのページ分割は、ng-repeat
のlimitTo
フィルターを使用して行うことができます。
例 巨大なデータセット(angular.js)でngRepeatのパフォーマンスを向上させる方法? この記事にも jsbinの例 がリンクされています。
また、すべての$ digestで評価されるため、データ提供にインラインメソッドを使用しないようにしてください。
<li ng-repeat="item in filteredItems()"> // Bad idea, since very often evaluated.
<li ng-repeat="item in items"> // Way to go!
別の明白な解決策は、特定の要素のバインディングを削除することです。確かにこれは、更新がビューに反映されなくなることを意味します。
bindonceソリューションは、双方向のバインディングを削除するだけではありません。基本的に、バインディングが削除される前に、値がバインドされるのを待ちます。よく読んでください。詳細は bindonceプロジェクト を確認してください。
上にリストされている記事には、2つのリストを処理するパターンに関する情報もあります。 1つは視覚化用、もう1つはデータソース用です。
Ng-grid
には、現在表示されている要素のみをレンダリングするという利点があります。詳しくは http://angular-ui.github.io/ng-grid/ をご覧ください。
同様のng-if
は、DOMツリーから非表示の要素を完全に削除しますが、ng-show
は、それらをそのままの状態に保つだけで非表示にします。 ng-if
を使用すると、元の要素(変更ではなく元が重要)のコピーが再度表示されるときに配置されます。
この記事には、リストをフィルタリングするためのいくつかの素晴らしいヒントもあります。
この方法では、データのサブリストを作成する必要がないため、ng-show
を使用してフィルターで除外された要素を非表示にするのと同じです。
また、「ユーザー入力のデバウンス」と呼ばれる別の手法。最後のオプションは、ユーザーが入力を停止するまでフィルタリングを待機することです。 jsfiddleの例 を含みます。
その他のヒントは、リンクされた記事で見つけることができます。そこにもリソースがリストされているので、それは良い出発点になるはずです。最も明白な1回と素早い勝利がここにリストされています。
もう1つの素晴らしい記事は AngularJSでデータバインディングはどのように機能するのですか?
少し遅れますが、これでうまくいくかもしれません:
https://github.com/Pasvaz/bindonce
変更する必要のないバインディングで使用できるため、$ digestはそれらを処理しなくなります。
angular 1.3以上では、次を使用して一度バインドできます::他のサードパーティのjsを使用する必要はありません
<li ng-repeat="item in :: items">
これは、アイテムが変更されない場合に適しているため、一度バインドできます。
データグリッドコンポーネントでリスナーの数が1000を超えたときに、パフォーマンスの問題が発生しました。
React.jsを使用してビューを構築するディレクティブを使用して、この問題を解決しました。ディレクティブは更新関数を公開しました。
データが(コントローラーで)変更されるたびに、更新関数がディレクティブをトリガーし、react.jsエンジンが効率的にレンダリングを実行しました。
angularプロジェクト内で2番目の主要なフレームワークを使用することは大きなオーバーヘッドであり、これは実際のデータバインディングの魔法ではありませんが、はるかに高速に動作します。
最終的に、angular.jsの使用をやめ、react.js + FLUXに移動しました。私はその方が良いと思いますが、角度からシフトするのは簡単ではありませんが、それだけの価値があります。
私はこれに数週間取り組んできました。 2つのことが大きな違いを生んでいることがわかりました。
(i)ワンタイムバインディング:可能な場合はワンタイムバインディングを使用します。 (ii)DEBOUNCE:すぐに伝播する必要はないが250ミリ秒待機できる入力の場合、デバウンス設定を設定します。これは、私の大きなng-repeatテーブルに信じられないほどの違いをもたらしました。私はデバウンス設定がどれほど効果的だったかを強調することはできません。 (ここを参照: https://docs.angularjs.org/api/ng/directive/ngModelOptions )
時計の数を制限することは、多くの場合長い道のりになります。時計の数を減らすのに効果的なテクニックの概要は次のとおりです
http://www.syntaxsuccess.com/viewarticle/547a8ba2c26c307c614c715e
bject.observe()は、ブラウザに真のデータバインディングを提供するために提案されているメカニズムです。オブジェクトおよび配列への変更を監視するメカニズムを公開し、これらのオブジェクトに加えられた変更を他のユーザーに通知します。
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<title>Object.observe()</title>
<link rel="stylesheet" href="../css/main.css" />
</head>
<body>
<div id="container">
<h1><a href="https://shailendrapathakbits.wordpress.com/" title="code_lab_by_shail ">code_lab_by_shail</a> Object.observe()</h1>
<p>An object <code>o</code> is created and <code>Object.observe()</code> is called on it.</p>
<p>Three changes are made to <code>o</code> and <code>Object.observe()</code> records these changes as shown below.</p>
<p>Use the console to find out what happens if you make further changes to <code>o</code>: it's defined in global scope.</p>
<p>Call <code>Object.unobserve(o, observer)</code> to stop observing changes.</p>
<p id="data" style="font-size: 14px;"></p>
<script src="js/main.js"></script>
<a href="https://github.com/shailendra9/objectobserver/blob/master/index.html" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
</div>
<script src="../js/lib/ga.js"></script>
</body>
</html>
デバッグデータを無効にする によって一般的にパフォーマンスを向上させることもできます
大きなデータを含むng-gridでパフォーマンスの問題がありました。それを Angular Grid に置き換えることで解決しました。そのWebサイトのデモでは、100,000行を簡単に管理できることが示されています。