当范围被破坏时,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 = []; ...
因此, $$watchers
arrays被清空(范围从范围层次结构中删除)。
从数组中删除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(); }); }
它使用元素销毁事件反过来破坏范围。