$scopeオブジェクトをダーティチェックする
Angular arrayは$scopeオブジェクトのウォッチャーをシンプルに維持します。検査$scopeするarrayと、呼び出されたが含まれていることがわかります$$watchers。
各ウォッチャーは、objectとりわけ、
- ウォッチャーが監視している式。これは単なる
attribute名前の場合もあれば、もっと複雑なものの場合もあります。
- 式の最後の既知の値。これは、式の現在の計算値に対してチェックできます。値が異なる場合、ウォッチャーは関数をトリガーし、
$scopeダーティとしてマークします。
- ウォッチャーが汚れている場合に実行される関数。
ウォッチャーの定義方法
AngularJSでウォッチャーを定義するには、さまざまな方法があります。
明示的$watchにattributeon することができ$scopeます。
$scope.$watch('person.username', validateUnique);
{{}}テンプレートに補間を配置できます(現在のにウォッチャーが作成されます$scope)。
<p>username: {{person.username}}</p>
ng-modelウォッチャーを定義するなどのディレクティブを要求できます。
<input ng-model="person.username" />
$digestサイクルは、彼らの最後の値に対するすべてのウォッチャーをチェックします
通常のチャネル(ng-model、ng-repeatなど)を介してAngularJSとやり取りすると、ディレクティブによってダイジェストサイクルがトリガーされます。
ダイジェストサイクルは、そのすべての子の深さ優先のトラバーサルです$scope。それぞれについて$scope object、繰り返し処理を行い$$watchers array、すべての式を評価します。新しい式の値が最後の既知の値と異なる場合、ウォッチャーの関数が呼び出されます。この関数は、DOMの一部を再コンパイルし、の値を再計算し$scope、をトリガーしAJAX request、必要なものを何でも実行できます。
すべてのスコープがトラバースされ、すべての監視式が最後の値に対して評価およびチェックされます。
ウォッチャーがトリガーされると、$scopeダーティです
ウォッチャーがトリガーされると、アプリは変更があったことを認識し$scope、ダーティとしてマークされます。
監視関数は$scope、親または親の他の属性を変更できます$scope。1つの$watcher関数がトリガーされた場合、他$scopeのがまだクリーンであることを保証できないため、ダイジェストサイクル全体を再度実行します。
これは、AngularJSに双方向バインディングがあるため、データを$scopeツリーに戻すことができるためです。$scopeすでに消化されているより高い値を変更する場合があります。おそらく、の値を変更します$rootScope。
$digestが汚れている場合は、$digestサイクル全体を再度実行します
$digestダイジェストサイクルがクリーンになるまで(すべての$watch式は前のサイクルと同じ値になります)、またはダイジェストの制限に達するまで、サイクルをループし続けます。デフォルトでは、この制限は10に設定されています。
ダイジェストの制限に達すると、AngularJSによってコンソールでエラーが発生します。
10 $digest() iterations reached. Aborting!
ダイジェストはマシンでは難しいですが、開発者にとっては簡単です
ご覧のとおり、AngularJSアプリで何かが変更されるたびに、AngularJSは$scope階層内のすべてのウォッチャーをチェックして、応答方法を確認します。開発者にとってこれは非常に生産性の恩恵です。配線コードをほとんど作成する必要がないので、AngularJSは値が変更されたかどうかに気づき、アプリの残りの部分をその変更に一致させます。
マシンの観点からすると、これは非常に非効率的であり、あまりにも多くのウォッチャーを作成すると、アプリケーションの速度が低下します。Miskoは、アプリが古いブラウザーで遅く感じる前に、約4000人のウォッチャーの数字を引用しています。
この制限は、たとえばng-repeat大きなものJSON arrayを超えた場合に簡単に到達できます。ウォッチャーを作成せずにテンプレートをコンパイルするワンタイムバインディングなどの機能を使用して、これを軽減できます。
あまりにも多くのウォッチャーを作成しないようにする方法
ユーザーがアプリを操作するたびに、アプリ内のすべてのウォッチャーが少なくとも1回評価されます。AngularJSアプリの最適化の大きな部分は、$scopeツリー内のウォッチャーの数を減らすことです。これを行う簡単な方法の1つは、1回限りのバインディングです。
ほとんど変更されないデータがある場合は、次のように::構文を使用して一度だけバインドできます。
<p>{{::person.username}}</p>
または
<p ng-bind="::person.username"></p>
バインディングは、含まれているテンプレートがレンダリングされ、データがに読み込まれたときにのみトリガーされ$scopeます。
これは、ng-repeatアイテム数が多い場合に特に重要です。
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>