我的AngularJs应用程序遇到了一个大问题......
我从服务器加载HTML内容(自定义表单)。
当然,加载的HTML包含一些ng-show
,ng-click
等...
所以,我在编译之前将其编译成我的页面
这很好用。
但是,每当我$compile
加载HTML时,它会在我的范围中添加更多$$watchers
(当然是ng-show观察者)。
这里有一点演示/模拟:http://plnkr.co/edit/6sSazsFAugzE5XmcYkS7
我的问题:如果您点击数百次“加载一些”,$$watchers
将永远不会减少并导致内存泄漏。
我尝试了remove()
,empty()
,unbind()
我的元素(链接),但$$观察者数组只是不断增长,永远不会被清理。
如何解决该问题?我怎样才能清理无用的观察者或“无编译”?
感谢您的帮助!!!
答案 0 :(得分:2)
由于新元素是从相同的范围和同一元素编译的,因此永远不会删除观察者。
当他们的范围被销毁(scope.$destroy()
)时,所有观察者都会被删除,这会在删除元素时自动发生。但是,您的元素永远不会被删除,您不断用新节点替换它。
避免这种情况的一种干净方法是避免重新编译每个新链接,而是生成动态ng-repeat
列表。
否则,如果要保留代码,可以在每次编译时为元素创建一个新范围。这样,当重新编译它时,前一个范围将被销毁并且所有观察者都被删除。
你可以看到这里的行动。我所做的就是在编译调用中用scope
替换scope.$new()
,以便每次都为元素设置一个新范围:
http://plnkr.co/edit/PvUAYyb0IUoaT3dVmpGM?p=preview
PS:这是一个我从未遇到的有趣用例,它可以为Angular社区做出贡献: - )
答案 1 :(得分:0)
要正确销毁已编译元素的scope
,您需要执行scope.$destroy()
。我建议的解决方案是创建一个继承的范围并在之后销毁它:
// if there was already an inherited scope, destroy it properly with $destroy()
if (scope.inheritedScope) scope.inheritedScope.$destroy();
// create new inherited scope every time
scope.inheritedScope = scope.$new(false);
// use it in the compile
$compile(element.contents())(scope.inheritedScope);
使用此解决方案的代码分叉: http://plnkr.co/edit/fOOHUGesbHYRiRWeLwKC
使用element.html
替换HTML并且只执行scope.$new
是不够的。我遇到了一个非常类似的情况,指令更复杂。一旦被替换,这个指令仍然会产生错误,所以我知道它仍然存在于内存中。