And*_*rew 53 javascript angularjs angularjs-directive angularjs-scope
目前正在开展一个项目,当我们发现大量内存泄漏时,不清除已销毁范围内的广播订阅.以下代码修复了此问题:
var onFooEventBroadcast = $rootScope.$on('fooEvent', doSomething);
scope.$on('$destroy', function() {
//remove the broadcast subscription when scope is destroyed
onFooEventBroadcast();
});
Run Code Online (Sandbox Code Playgroud)
这种做法是否也应该用于手表?代码示例如下:
var onFooChanged = scope.$watch('foo', doSomething);
scope.$on('$destroy', function() {
//stop watching when scope is destroyed
onFooChanged();
});
Run Code Online (Sandbox Code Playgroud)
gka*_*pak 87
不,您不需要删除$$watchers,因为一旦范围被销毁,它们将被有效地删除.
从角的源代码(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 = [];
...
Run Code Online (Sandbox Code Playgroud)
因此,$$watchers清空数组(并从范围层次结构中移除范围).
watcher无论如何,从数组中删除所有取消注册函数都会执行:
$watch: function(watchExp, listener, objectEquality) {
...
return function deregisterWatch() {
arrayRemove(array, watcher);
lastDirtyWatch = null;
};
}
Run Code Online (Sandbox Code Playgroud)
因此,取消注册$$watchers"手动" 是没有意义的.
您仍然应该取消注册事件侦听器(正如您在帖子中正确提到的那样)!
注意:
您只需要取消注册在其他范围上注册的侦听器.无需取消注册正在销毁的作用域上的侦听器.
例如:
// You MUST unregister these
$rootScope.$on(...);
$scope.$parent.$on(...);
// You DON'T HAVE to unregister this
$scope.$on(...)
Run Code Online (Sandbox Code Playgroud)
(感谢@John 指出它)
此外,请确保从与被销毁范围相比的元素中取消注册任何事件侦听器.例如,如果您有一个指令在父节点上或在其上注册一个侦听器<body>,那么您也必须取消注册它们.
同样,您不必删除在要销毁的元素上注册的侦听器.
与原始问题无关的类型,但现在还有一个$destroyed事件在被销毁的元素上发送,所以你也可以挂钩(如果它适合你的用例):
link: function postLink(scope, elem) {
doStuff();
elem.on('$destroy', cleanUp);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
26971 次 |
| 最近记录: |