Controllando sporco l' $scope
oggetto
Angolare mantiene un semplice array
osservatore negli $scope
oggetti. Se ispezionate qualcuno $scope
, troverete che contiene un array
chiamato $$watchers
.
Ogni osservatore è uno object
che contiene tra l'altro
- Un'espressione che l'osservatore sta monitorando. Questo potrebbe essere solo un
attribute
nome 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à
$scope
come 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 $watch
un attribute
on $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-model
definire l'osservatore per te.
<input ng-model="person.username" />
Il $digest
ciclo 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 $scope
e di tutti i suoi figli . Per ognuno $scope
object
, ripetiamo il suo $$watchers
array
e 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 $scope
o su un genitore $scope
. Se una $watcher
funzione è stata attivata, non possiamo garantire che le altre $scope
siano 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 $scope
sull'albero. Potremmo modificare un valore su un valore superiore $scope
che è già stato digerito. Forse cambiamo un valore su $rootScope
.
Se $digest
è sporco, eseguiamo $digest
nuovamente l'intero ciclo
Facciamo un ciclo continuo attraverso il $digest
ciclo fino a quando il ciclo digest non viene pulito (tutte le $watch
espressioni 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 $scope
gerarchia 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-repeat
supera 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 $scope
albero. 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-repeat
con molti articoli.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>