Travaille actuellement sur un projet où nous avons trouvé d'énormes fuites de mémoire en n'effaçant pas les abonnements de diffusion des étendues détruites. Le code suivant a résolu ce problème:
var onFooEventBroadcast = $rootScope.$on('fooEvent', doSomething);
scope.$on('$destroy', function() {
//remove the broadcast subscription when scope is destroyed
onFooEventBroadcast();
});
Cette pratique devrait-elle également être utilisée pour les montres? Exemple de code ci-dessous:
var onFooChanged = scope.$watch('foo', doSomething);
scope.$on('$destroy', function() {
//stop watching when scope is destroyed
onFooChanged();
});
Non, vous n'avez pas besoin de supprimer $$watchers
, car ils seront effectivement supprimés une fois la portée détruite.
À partir du code source d'Angular (v1.2.21), Scope
's $destroy
méthode:
$destroy: function() {
...
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
...
this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
...
Alors le $$watchers
le tableau est vidé (et la portée est supprimée de la hiérarchie des portées).
La suppression de watcher
du tableau est de toute façon la fonction de désinscription:
$watch: function(watchExp, listener, objectEquality) {
...
return function deregisterWatch() {
arrayRemove(array, watcher);
lastDirtyWatch = null;
};
}
Il est donc inutile de désenregistrer le $$watchers
"manuellement".
Vous devez toujours désinscrire les auditeurs d'événements (comme vous le mentionnez correctement dans votre message)!
REMARQUE: Il vous suffit de désinscrire les écouteurs enregistrés sur d'autres étendues. Il n'est pas nécessaire de désenregistrer les écouteurs enregistrés sur la portée qui est détruite.
Par exemple.:
// You MUST unregister these
$rootScope.$on(...);
$scope.$parent.$on(...);
// You DON'T HAVE to unregister this
$scope.$on(...)
(Merci à @John pour en le signalant )
Assurez-vous également de désenregistrer les écouteurs d'événements des éléments qui survivent à la portée en cours de destruction. Par exemple. si vous avez une directive, enregistrez un écouteur sur le nœud parent ou sur <body>
, alors vous devez aussi les désinscrire.
Encore une fois, vous n'avez pas à supprimer un écouteur enregistré sur l'élément en cours de destruction.
Un peu sans rapport avec la question d'origine, mais maintenant il y a aussi un $destroyed
événement distribué sur l'élément en cours de destruction, vous pouvez donc vous y connecter également (si cela convient à votre cas d'utilisation):
link: function postLink(scope, elem) {
doStuff();
elem.on('$destroy', cleanUp);
}
Je voudrais ajouter aussi @ gkalpak la réponse car elle m'a conduit dans la bonne direction ..
L'application sur laquelle je travaillais a créé une fuite de mémoire en remplaçant les directives qui avaient des montres. Les directives ont été remplacées à l'aide de jQuery puis respectées.
Pour corriger j'ai ajouté la fonction de lien suivante
link: function (scope, elem, attrs) {
elem.on('$destroy', function () {
scope.$destroy();
});
}
il utilise l'événement destroy élément pour à son tour détruire la portée.