¿Cómo funciona el enlace de datos en AngularJS?
¿Cómo funciona la vinculación de datos en el marco AngularJS
?
No he encontrado detalles técnicos en su sitio. Está más o menos claro cómo funciona cuando los datos se propagan de la vista al modelo. Pero, ¿cómo hace AngularJS para seguir los cambios de las propiedades del modelo sin setters y getters?
He encontrado que hay JavaScript watchers que pueden hacer este trabajo. Pero no están soportados en Internet Explorer 6 y Internet Explorer 7. Entonces, ¿cómo sabe AngularJS que he cambiado, por ejemplo, lo siguiente y ha reflejado este cambio en una vista?
myobject.myproperty="new value";
1922
3
AngularJS recuerda el valor y lo compara con un valor anterior. Esto es una comprobación básica de la suciedad. Si hay un cambio en el valor, entonces dispara el evento de cambio.
El método
$apply()
, que es lo que se llama cuando se pasa de un mundo no-AngularJS a un mundo AngularJS, llama a$digest()
. Un resumen es simplemente una comprobación sucia. Funciona en todos los navegadores y es totalmente predecible.Para contrastar la comprobación sucia (AngularJS) frente a los escuchadores de cambios (KnockoutJS y Backbone.js): Mientras que el dirty-checking puede parecer simple, e incluso ineficiente (lo trataré más adelante), resulta que es semánticamente correcto todo el tiempo, mientras que los change listeners tienen muchos casos de esquina extraños y necesitan cosas como el seguimiento de dependencias para hacerlo más semánticamente correcto. El seguimiento de dependencias de KnockoutJS es una característica inteligente para un problema que AngularJS no tiene.
Problemas con los escuchadores de cambios:
¿Qué pasa con el rendimiento?
Puede parecer que somos lentos, ya que el dirty-checking es ineficiente. Aquí es donde tenemos que mirar los números reales en lugar de tener sólo argumentos teóricos, pero primero vamos a definir algunas restricciones.
Los humanos son:
Lentos - Todo lo que sea más rápido que 50 ms es imperceptible para los humanos y, por tanto, puede considerarse "instantáneo".
Limitado - Realmente no se puede mostrar más de unas 2000 piezas de información a un humano en una sola página. Todo lo que sea más que eso es una interfaz de usuario realmente mala, y los humanos no pueden procesar esto de todos modos.
Así que la verdadera pregunta es esta: ¿Cuántas comparaciones se pueden hacer en un navegador en 50 ms? Es una pregunta difícil de responder, ya que entran en juego muchos factores, pero he aquí un caso de prueba: http://jsperf.com/angularjs-digest/6 que crea 10.000 observadores. En un navegador moderno esto tarda algo menos de 6 ms. En Internet Explorer 8 tarda unos 40 ms. Como puedes ver, esto no es un problema ni siquiera en los navegadores lentos de hoy en día. Hay una advertencia: las comparaciones deben ser sencillas para ajustarse al límite de tiempo... Desgraciadamente es demasiado fácil añadir una comparación lenta en AngularJS, por lo que es fácil construir aplicaciones lentas cuando no se sabe lo que se está haciendo. Pero esperamos tener una respuesta proporcionando un módulo de instrumentación, que te mostraría cuáles son las comparaciones lentas.
Resulta que los videojuegos y las GPUs utilizan el enfoque de comprobación sucia, específicamente porque es consistente. Mientras superen la tasa de refresco del monitor (normalmente 50-60 Hz, o cada 16,6-20 ms), cualquier rendimiento por encima de eso es un desperdicio, así que es mejor dibujar más cosas, que conseguir más FPS.
Este es mi entendimiento básico. Puede que esté equivocado.
$watch
.$apply
.$digest
que recorre cada uno de los que recorre cada uno de los relojes y comprueba si han cambiado desde la última vez que se ejecutó el$digest
.En el desarrollo normal, la sintaxis de enlace de datos en el HTML le dice al compilador de AngularJS que cree los relojes por ti y los métodos del controlador ya se ejecutan dentro de
$apply
. Así que para el desarrollador de la aplicación es todo transparente.Yo mismo me he preguntado esto durante un tiempo. Sin setters, ¿cómo se da cuenta
AngularJS
de los cambios en el objeto$scope
? ¿Los sondea?Lo que hace en realidad es lo siguiente: Cualquier lugar "normal" en el que modifiques el modelo ya ha sido llamado desde las tripas de
AngularJS
, así que automáticamente llama a$apply
por ti después de que tu código se ejecute. Digamos que tu controlador tiene un método que está conectado ang-click
en algún elemento. ComoAngularJS
conecta la llamada de ese método por ti, tiene la oportunidad de hacer una$apply
en el lugar apropiado. Igualmente, para las expresiones que aparecen justo en las vistas, éstas son ejecutadas porAngularJS
para que haga el$apply
.Cuando la documentación habla de tener que llamar a
$apply
manualmente para código fuera deAngularJS
, está hablando de código que, cuando se ejecuta, no proviene del propioAngularJS
en la pila de llamadas.