AngularJS – ¿Destruye $ los remove event listeners?

https://docs.angularjs.org/guide/directive

Al escuchar este evento, puede eliminar los detectores de eventos que puedan causar pérdidas de memoria. Los oyentes registrados en ámbitos y elementos se limpian automáticamente cuando se destruyen, pero si registró un oyente en un servicio o registró un oyente en un nodo DOM que no se está eliminando, tendrá que limpiarlo usted mismo o te arriesgas a introducir una pérdida de memoria.

Mejores prácticas: las directivas deberían limpiarse después de ellas mismas. Puede usar element.on (‘$ destroy’, …) o scope. $ On (‘$ destroy’, …) para ejecutar una función de limpieza cuando se elimina la directiva.

Pregunta:

Tengo un element.on "click", (event) -> dentro de mi directiva:

  1. Cuando se destruye la directiva, ¿hay referencias de memoria al element.on para evitar que se recolecte basura?
  2. La documentación angular establece que debo usar un controlador para eliminar los detectores de eventos en el evento $destroy emitido. Tenía la impresión de que destroy() eliminó los oyentes del evento, ¿no es así?

Oyentes de eventos

En primer lugar, es importante comprender que hay dos tipos de “oyentes de eventos”:

  1. Audientes de eventos de scope registrados a través de $on :

     $scope.$on('anEvent', function (event, data) { ... }); 
  2. Controladores de eventos unidos a elementos a través de, por ejemplo, on :

     element.on('click', function (event) { ... }); 

$ scope. $ destroy ()

Cuando $scope.$destroy() se ejecuta, eliminará todos los oyentes registrados a través de $on en ese $ scope.

No eliminará los elementos DOM ni ningún manejador de eventos adjuntos del segundo tipo.

Esto significa que llamar $scope.$destroy() manualmente desde el ejemplo dentro de la función de enlace de una directiva no eliminará un controlador adjunto a través de, por ejemplo, element.on , ni el elemento DOM en sí.


element.remove ()

Tenga en cuenta que remove es un método jqLite (o un método jQuery si jQuery se carga antes de AngularjS) y no está disponible en un Objeto de elemento DOM estándar.

Cuando se element.remove() ese elemento y todos sus elementos element.remove() se eliminarán del DOM juntos y todos los controladores de eventos se adjuntarán, por ejemplo, a element.on .

No destruirá el $ scope asociado con el elemento.

Para hacerlo más confuso también hay un evento jQuery llamado $destroy . A veces, cuando se trabaja con bibliotecas de jQuery de terceros que eliminan elementos, o si los elimina manualmente, es posible que deba realizar una limpieza cuando eso ocurra:

 element.on('$destroy', function () { scope.$destroy(); }); 

Qué hacer cuando una directiva es “destruida”

Esto depende de cómo se “destruye” la directiva.

Un caso normal es que una directiva se destruye porque ng-view cambia la vista actual. Cuando esto suceda, la directiva ng-view destruirá el $ scope asociado, cortará todas las referencias a su scope principal y llamará a remove() en el elemento.

Esto significa que si esa vista contiene una directiva con esto en su función de enlace cuando es destruida por ng-view :

 scope.$on('anEvent', function () { ... }); element.on('click', function () { ... }); 

Ambos oyentes de eventos se eliminarán automáticamente.

Sin embargo, es importante tener en cuenta que el código dentro de estos oyentes aún puede causar pérdidas de memoria, por ejemplo, si ha logrado las circular references comunes del patrón de fuga de memoria JS.

Incluso en este caso normal de una directiva que se destruye debido a un cambio de vista, hay cosas que puede necesitar para realizar una limpieza manual.

Por ejemplo, si ha registrado un oyente en $rootScope :

 var unregisterFn = $rootScope.$on('anEvent', function () {}); scope.$on('$destroy', unregisterFn); 

Esto es necesario ya que $rootScope nunca se destruye durante la vida de la aplicación.

Lo mismo ocurre si está utilizando otra implementación de pub / sub que no realiza automáticamente la limpieza necesaria cuando se destruye el $ scope, o si su directiva pasa devoluciones de llamadas a los servicios.

Otra situación sería cancelar $interval / $timeout :

 var promise = $interval(function () {}, 1000); scope.$on('$destroy', function () { $interval.cancel(promise); }); 

Si su directiva conecta controladores de eventos a elementos, por ejemplo, fuera de la vista actual, también debe limpiarlos manualmente:

 var windowClick = function () { ... }; angular.element(window).on('click', windowClick); scope.$on('$destroy', function () { angular.element(window).off('click', windowClick); }); 

Estos fueron algunos ejemplos de lo que se debe hacer cuando las directivas son “destruidas” por Angular, por ejemplo, por ng-view o ng-if .

Si tiene directivas personalizadas que administran el ciclo de vida de los elementos DOM, etc., por supuesto, se volverán más complejas.