Comprobando sucio el $scopeobjeto
Angular mantiene un simple arrayobservador en los $scopeobjetos. Si inspecciona alguno $scope, encontrará que contiene un arrayllamado $$watchers.
Cada observador es un objectque contiene entre otras cosas
- Una expresión que el observador está monitoreando. Esto podría ser solo un
attributenombre, 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á
$scopecomo 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 $watchun attributeencendido $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-modelque define al observador por usted.
<input ng-model="person.username" />
El $digestciclo 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 $scopetodos sus hijos . Para cada uno $scope object, iteramos sobre él $$watchers arrayy 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, $scopeestá sucio
Si se activa un observador, la aplicación sabe que algo ha cambiado y $scopeestá marcado como sucio.
Las funciones de vigilante pueden cambiar otros atributos en $scopeo en un padre $scope. Si se $watcherha activado una función, no podemos garantizar que nuestras otras $scopeesté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 $scopeque ya ha sido digerido. Quizás cambiemos un valor en el $rootScope.
Si $digestestá sucio, ejecutamos todo el $digestciclo nuevamente
Continuamente recorremos el $digestciclo hasta que el ciclo de resumen salga limpio (todas las $watchexpresiones 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 $scopejerarquí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-repeatsupera un gran, JSON arraypor 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-repeatmuchos artículos.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>