Should the angular $ clock be removed when the region is destroyed?

We are currently working on a project where we have discovered huge memory leaks when we do not clear the mailing list subscriptions of the destroyed areas. The following code fixed this:

var onFooEventBroadcast = $rootScope.$on('fooEvent', doSomething); scope.$on('$destroy', function() { //remove the broadcast subscription when scope is destroyed onFooEventBroadcast(); }); 

Should this practice also be used for watches? Sample code below:

 var onFooChanged = scope.$watch('foo', doSomething); scope.$on('$destroy', function() { //stop watching when scope is destroyed onFooChanged(); }); 
+45
javascript angularjs angularjs-scope angularjs-directive
Aug 4 '14 at 7:44
source share
2 answers

No, you do not need to delete $$watchers , as they will be effectively deleted after the destruction of the area.

From Angular source code (v1.2.21), Scope $destroy method:

 $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 = []; ... 

So, the $$watchers array is omitted (and the region is removed from the region hierarchy).

Retrieving watcher from an array is all an unregistered function:

 $watch: function(watchExp, listener, objectEquality) { ... return function deregisterWatch() { arrayRemove(array, watcher); lastDirtyWatch = null; }; } 

So, it makes no sense to unregister $$watchers manually.




You should still unregister event listeners (as you correctly noted in your message)!

Note: You only need to unregister listeners registered in other areas. There is no need to unregister listeners registered in an area that is being destroyed.
For example:.

 // You MUST unregister these $rootScope.$on(...); $scope.$parent.$on(...); // You DON'T HAVE to unregister this $scope.$on(...) 

(thanks to @John for pointing this out )

Also, make sure you unregister any event listeners from elements that survive the destructible region. For example. if you have a directive, register the listener on the parent node or on <body> , then you must also unregister.
Again, you do not need to delete the listener registered on the element to be destroyed.




The view is not related to the original question, but now there is also the $destroyed event dispatched to the element to be destroyed, so you can also connect to it (if it suits your usecase):

 link: function postLink(scope, elem) { doStuff(); elem.on('$destroy', cleanUp); } 
+76
Aug 04 '14 at 7:56
source share
— -

I would also like to add @gkalpak's answer as it leads me in the right direction.

The application I was working on created a memory leak by replacing directives that had a clock. Directives were replaced with jQuery and then executed.

To fix, I added the following link function

 link: function (scope, elem, attrs) { elem.on('$destroy', function () { scope.$destroy(); }); } 

it uses an element destruction event to in turn destroy an area.

+1
Apr 04 '17 at 2:04 on
source share



All Articles