Comprobando sucio el $scope
objeto
Angular mantiene un simple array
observador en los $scope
objetos. Si inspecciona alguno $scope
, encontrará que contiene un array
llamado $$watchers
.
Cada observador es un object
que contiene entre otras cosas
- Una expresión que el observador está monitoreando. Esto podría ser solo un
attribute
nombre, o algo más complicado.
- Un último valor conocido de la expresión. Esto se puede verificar con el valor calculado actual de la expresión. Si los valores difieren, el observador activará la función y la marcará
$scope
como sucia.
- Una función que se ejecutará si el observador está sucio.
Cómo se definen los observadores
Hay muchas formas diferentes de definir un observador en AngularJS.
Puede explícitamente $watch
un attribute
encendido $scope
.
$scope.$watch('person.username', validateUnique);
Puede colocar una {{}}
interpolación en su plantilla (se creará un observador para usted en la actual $scope
).
<p>username: {{person.username}}</p>
Puede solicitar una directiva como la ng-model
que define al observador por usted.
<input ng-model="person.username" />
El $digest
ciclo verifica a todos los observadores contra su último valor
Cuando interactuamos con AngularJS a través de los canales normales (ng-model, ng-repeat, etc.) la directiva activará un ciclo de resumen.
Un ciclo de digestión es un recorrido profundo y primero de $scope
todos sus hijos . Para cada uno $scope
object
, iteramos sobre él $$watchers
array
y evaluamos todas las expresiones. Si el nuevo valor de expresión es diferente del último valor conocido, se llama a la función del observador. Esta función podría recompilar parte del DOM, recalcular un valor $scope
, activar un AJAX
request
, cualquier cosa que necesite hacer.
Se recorre cada ámbito y cada expresión de observación se evalúa y se compara con el último valor.
Si se activa un observador, $scope
está sucio
Si se activa un observador, la aplicación sabe que algo ha cambiado y $scope
está marcado como sucio.
Las funciones de vigilante pueden cambiar otros atributos en $scope
o en un padre $scope
. Si se $watcher
ha activado una función, no podemos garantizar que nuestras otras $scope
estén todavía limpias, por lo que ejecutamos todo el ciclo de resumen nuevamente.
Esto se debe a que AngularJS tiene un enlace bidireccional, por lo que los datos se pueden volver a pasar al $scope
árbol. Podemos cambiar un valor en un valor superior $scope
que ya ha sido digerido. Quizás cambiemos un valor en el $rootScope
.
Si $digest
está sucio, ejecutamos todo el $digest
ciclo nuevamente
Continuamente recorremos el $digest
ciclo hasta que el ciclo de resumen salga limpio (todas las $watch
expresiones tienen el mismo valor que tenían en el ciclo anterior) o alcanzamos el límite de resumen. Por defecto, este límite se establece en 10.
Si alcanzamos el límite de resumen, AngularJS generará un error en la consola:
10 $digest() iterations reached. Aborting!
El resumen es difícil para la máquina pero fácil para el desarrollador
Como puede ver, cada vez que algo cambia en una aplicación AngularJS, AngularJS verificará a cada observador en la $scope
jerarquía para ver cómo responder. Para un desarrollador, esto es una gran ayuda para la productividad, ya que ahora necesita escribir casi ningún código de cableado, AngularJS solo notará si un valor ha cambiado y hará que el resto de la aplicación sea consistente con el cambio.
Desde la perspectiva de la máquina, aunque esto es muy ineficiente y ralentizará nuestra aplicación si creamos demasiados observadores. Misko ha citado una cifra de aproximadamente 4000 observadores antes de que su aplicación parezca lenta en navegadores antiguos.
Este límite es fácil de alcanzar si ng-repeat
supera un gran, JSON
array
por ejemplo. Puede mitigar esto usando características como el enlace único para compilar una plantilla sin crear observadores.
Cómo evitar crear demasiados observadores
Cada vez que su usuario interactúa con su aplicación, cada observador en su aplicación será evaluado al menos una vez. Una gran parte de la optimización de una aplicación AngularJS es reducir la cantidad de observadores en su $scope
árbol. Una manera fácil de hacer esto es con un enlace único .
Si tiene datos que rara vez cambiarán, puede vincularlos solo una vez usando la sintaxis ::, así:
<p>{{::person.username}}</p>
o
<p ng-bind="::person.username"></p>
El enlace solo se activará cuando se represente la plantilla que contiene y se carguen los datos $scope
.
Esto es especialmente importante cuando tienes ng-repeat
muchos artículos.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>