Controllando sporco l' $scopeoggetto
Angolare mantiene un semplice arrayosservatore negli $scopeoggetti. Se ispezionate qualcuno $scope, troverete che contiene un arraychiamato $$watchers.
Ogni osservatore è uno objectche contiene tra l'altro
- Un'espressione che l'osservatore sta monitorando. Questo potrebbe essere solo un
attributenome o qualcosa di più complicato.
- Un ultimo valore noto dell'espressione. Questo può essere verificato rispetto al valore calcolato corrente dell'espressione. Se i valori differiscono, l'osservatore attiverà la funzione e contrassegnerà
$scopecome sporco.
- Una funzione che verrà eseguita se l'osservatore è sporco.
Come sono definiti gli osservatori
Esistono molti modi diversi per definire un osservatore in AngularJS.
Puoi esplicitamente $watchun attributeon $scope.
$scope.$watch('person.username', validateUnique);
Puoi inserire {{}}un'interpolazione nel tuo modello (un watcher verrà creato per te sull'attuale $scope).
<p>username: {{person.username}}</p>
Puoi chiedere una direttiva tale da ng-modeldefinire l'osservatore per te.
<input ng-model="person.username" />
Il $digestciclo controlla tutti gli osservatori rispetto al loro ultimo valore
Quando interagiamo con AngularJS attraverso i normali canali (ng-model, ng-repeat, ecc.) Un ciclo digest verrà attivato dalla direttiva.
Un ciclo digest è un attraversamento in profondità di $scopee di tutti i suoi figli . Per ognuno $scope object, ripetiamo il suo $$watchers arraye valutiamo tutte le espressioni. Se il nuovo valore di espressione è diverso dall'ultimo valore noto, viene chiamata la funzione di watcher. Questa funzione potrebbe ricompilare parte del DOM, ricalcolare un valore $scope, attivare un AJAX request, tutto ciò che è necessario per farlo.
Ogni ambito viene attraversato e ogni espressione di controllo viene valutata e verificata rispetto all'ultimo valore.
Se viene attivato un osservatore, $scopeè sporco
Se viene attivato un osservatore, l'app sa che qualcosa è cambiato e che $scopeè contrassegnato come sporco.
Le funzioni di watcher possono modificare altri attributi su $scopeo su un genitore $scope. Se una $watcherfunzione è stata attivata, non possiamo garantire che le altre $scopesiano ancora pulite e quindi eseguiamo nuovamente l'intero ciclo di digest.
Questo perché AngularJS ha un'associazione a due vie, quindi i dati possono essere trasferiti $scopesull'albero. Potremmo modificare un valore su un valore superiore $scopeche è già stato digerito. Forse cambiamo un valore su $rootScope.
Se $digestè sporco, eseguiamo $digestnuovamente l'intero ciclo
Facciamo un ciclo continuo attraverso il $digestciclo fino a quando il ciclo digest non viene pulito (tutte le $watchespressioni hanno lo stesso valore che avevano nel ciclo precedente) o raggiungiamo il limite digest. Per impostazione predefinita, questo limite è impostato su 10.
Se raggiungiamo il limite digest, AngularJS genererà un errore nella console:
10 $digest() iterations reached. Aborting!
Il digest è difficile sulla macchina ma facile per lo sviluppatore
Come puoi vedere, ogni volta che qualcosa cambia in un'app AngularJS, AngularJS controllerà ogni singolo osservatore nella $scopegerarchia per vedere come rispondere. Per uno sviluppatore questo è un grande vantaggio per la produttività, poiché ora è necessario scrivere quasi nessun codice di cablaggio, AngularJS noterà solo se un valore è cambiato e renderà il resto dell'app coerente con la modifica.
Dal punto di vista della macchina, tuttavia, questo è estremamente inefficiente e rallenterà la nostra app se creiamo troppi osservatori. Misko ha citato una cifra di circa 4000 osservatori prima che la tua app sembrerà lenta sui browser più vecchi.
Questo limite è facile da raggiungere, ad esempio se si ng-repeatsupera un grande JSON array. È possibile attenuare ciò utilizzando funzionalità come l'associazione una tantum per compilare un modello senza creare osservatori.
Come evitare di creare troppi osservatori
Ogni volta che l'utente interagisce con la tua app, ogni singolo watcher nella tua app verrà valutato almeno una volta. Una parte importante dell'ottimizzazione di un'app AngularJS è la riduzione del numero di osservatori nel tuo $scopealbero. Un modo semplice per farlo è con l' associazione una volta .
Se disponi di dati che cambieranno raramente, puoi collegarli solo una volta usando la sintassi ::, in questo modo:
<p>{{::person.username}}</p>
o
<p ng-bind="::person.username"></p>
L'associazione verrà attivata solo quando viene eseguito il rendering del modello contenitore e vengono caricati i dati $scope.
Ciò è particolarmente importante quando si dispone di un ng-repeatcon molti articoli.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>