当范围被破坏时,angular度$ watch应该被移除吗?

目前正在开发一个项目,当我们没有将广播订阅从已销毁的范围中清除时,我们发现了巨大的内存泄漏。 下面的代码解决了这个问题:

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

这种做法是否也适用于手表? 下面的代码示例:

 var onFooChanged = scope.$watch('foo', doSomething); scope.$on('$destroy', function() { //stop watching when scope is destroyed onFooChanged(); }); 

不,您不需要移除$$watchers ,因为一旦范围被破坏,它们将被有效地移除。

从Angular的源代码(v1.2.21)中, Scope$destroy方法:

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

因此, $$watchersarrays被清空(范围从范围层次结构中删除)。

从数组中删除watcher是所有的注销function无论如何:

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

所以,“手动”注销$$watchers是毫无意义的。


你仍然应该取消注册事件监听器(正如你在你的文章中正确提到的那样)!

注意:您只需注销在其他范围注册的侦听器。 没有必要注销正在被销毁的范围上注册的监听者。
例如:

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

(Thx给@John 指出来 )

此外,请确保您从超出被销毁范围的元素注销任何事件侦听器。 例如,如果你有一个指令在父节点或<body>上注册一个监听器,那么你也必须取消注册它们。
同样,您不必删除正在销毁的元素上注册的侦听器。


与原来的问题无关,但是现在还有一个被销毁的元素被销毁,所以你可以挂钩(如果它适合你的用例):

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

我想补充@gkalpak的答案,因为它使我朝着正确的方向前进。

我正在做的应用程序通过replace手表的指令来创build内存泄漏。 指令被replace使用jQuery,然后complied。

为了解决我添加了以下链接function

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

它使用元素销毁事件反过来破坏范围。