$watch y $digest: Entendiendo el servicio $scope de AngularJS

angular_0

Una de las funcionalidades que más han ayudado para que los desarrolladores se decanten por el uso de AngularJS ha sido la posibilidad de realizar el doble ‘data-binding’. Con el doble ‘data-binding’ tenemos la posibilidad de enlazar un elemento de la vista con un modelo JSON disponible en la lógica de negocio de nuestra aplicación.

Con este enlazado lo que conseguimos es que cuando nuestro modelo cambie, la vista actualice los datos en el HTML de una forma transparente, sin que nosotros, como desarrolladores, tengamos que indicarle nada más al framework sobre el enlazado. De igual forma ocurre cuando el cambio del modelo se realiza desde la vista. Cuando el usuario modifica un dato de un modelo enlazado, este se actualiza transparentemente.

Este enlazado se consigue con uno de los elementos más importante con los que cuenta actualmente las versiones de AngularJS, el servicio $scope. Este servicio es el pegamento que unirá la lógica con la interfaz de nuestra aplicación. Cuando nosotros queramos que modelos y variables sean enlazados desde las vista, simplemente se lo tendremos que indicar al $scope.

Este factor, como decimos, suele ser un grandísimo atractivo del framework y la mejor manera de despreocuparnos a la hora de enlazar los objetos JSON contra el HTML. Sin embargo, esta ‘magia’ que desprende, puede llegar a suponernos problemas de rendimiento a largo plazo si no entendemos bien lo que ocurre por debajo del $scope. Para entender mejor la manera en que trabaja el $scope tenemos que explicar antes  dos métodos con los que contamos en AngularJS: $watch y $digest.

$watch: Listeners en los modelos

El método $watch se encarga de registrar un ‘listener’ (he preferido no traducir el término al castellano por ser más usado su versión inglesa) sobre la propiedad que indiquemos. Cada vez que realicemos un cambio sobre la variable registrada en $watch, se lanzará una función callback que realiza las acciones definidas. El servicio $scope, internamente, realiza una llamada a $watch para que escuche en cada objeto o variable que hayamos definido en él. Cada vez que se realiza un cambio, $watch se encargará del repintado de la interfaz de ese elemento.

$digest: Comprobando los cambios

Con solo esto no destapamos toda la magia que existe en torno a los $scopes, pues que tengamos el observador $watch nos dice poco de cómo o cuando se lanza su función callback. Es decir, ¿Cómo sabe AngularJS que un modelo ha cambiado para lanzar su función de escucha? Para realizar esto, Angular cuenta internamente con un elemento denominado $digest. Este nuevo elemento se encargará de lanzarse durante momentos determinados e irá comprobando si hay cambios en los modelos incluidos en el $scope para lanzar sus funciones de escucha. Pero ¿Cuándo empieza $digest a ejecutarse o quien provoca que $digest se ejecute?

El proceso de $digest empieza cuando se llama a $scope.$digest(). A este método se llama implícitamente, por ejemplo, cuando realizamos un cambio del $scope en un evento registrado por la directiva ng-click.  El proceso comprobará si existen cambios en los modelos y de ser así lanzará la función de escucha registrada en el $watch. De esta forma cuando el usuario realice acciones, se actualizarán los modelos y se reflejarán en la interfaz. Imaginemos otro ejemplo. En esta ocasión hemos registrado un evento con la directiva ng-keypress. Esta directiva lanzará $scope.$digest() cada vez que presionemos sobre una tecla en el lugar especificado.

El problema de este comportamiento puede venir cuando en las acciones internas de estos  listeners, cambiemos modelos que se encuentren dentro de nuestro $scope. ¿Qué ocurre en este caso? Pues que Angular, por implementación implícita, cada vez que termina de ejecutar un listener, vuelve a lanzar el proceso $digest para comprobar si el estado de algún modelo ha cambiado para, si se da el caso, lanzar su función de escucha. Este ciclo de vida  se reproducirá de esta forma, hasta que todos los  modelos del $scope se encuentren en estado ‘sin modificar’.

Conclusiones

Como podemos ver, la magia en este caso no existe y lo que AngularJS está haciendo por debajo es un grandísimo trabajo de procesamiento. Gracias a esto el trabajo de desarrollo es menor por lo general, pero tenemos que tener cuenta que el trabajo de procesamiento de la aplicación aumenta considerablemente. Tenemos que tener cuidado en cómo usamos los $scopes y cómo registramos nuestros $watch (podemos incluir escuchadores personalizados por nosotros) ya que según el uso que hagamos de ellos, tendremos aplicaciones peor o mejor optimizadas.

Google lleva tiempo trabajando en cambiar estos mecanismos. De ahí viene que quieran ser tan drásticos en cuanto al cambio de versión, pues quieren que en AngularJS 2 se delimite mucho en el uso de controladores que gestionen $scopes globales a la aplicación.Veremos si lo consiguen o si siguen con estos problemas de diseño.

Nos leemos 🙂

Imagen | portlandwebworks

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s