2016-03-18 30 views
2

在Angular.JS项目中,我有一个指令与一个复杂的模板,实例化数千次(在网格中)。Angular JS范围泄漏与element.empty()

由于性能原因,我不得不在多个子模板中拆分模板。根据指令的范围值组合,我选择一个子模板。

性能增益是真实的(在非常大的网格上大于100),但在某些情况下(当子模板包含ng-repeat指令时)Angular正在调用在删除的DOM元素范围内声明的函数。

我的问题归纳为以下最小代码:

angular.module('myApp', []).directive('myDirective', ['$compile', '$log', function ($compile, $log) { 
    function display(scopeId, x) { 
    $log.log('func called with', x, 'in scope', scopeId); 

    return x; 
    } 

    return { 
    scope: true, 
    link: function (scope, element) { 
     scope.array = [1, 2, 3]; 
     scope.display = display; 

     scope.$watch(function() { 
     return scope.abc; 
     }, function (newValue) { 
     var newContent = angular.element('<div ng-repeat="item in array">{{display($id, item)}}</div>'); 

     element.empty(); 

     element.append($compile(newContent)(scope)) 
     }); 
    } 
    }; 
}]); 

你可以在这里进行测试:https://jsfiddle.net/yss4yskm/6/

每次元素被替换(当你点击复选框),通过创建的每个范围ng-repeat被泄露:作用域继续登录到浏览器控制台,Batarang也显示泄漏的作用域。

不应该element.empty()删除所有的子范围?

为什么问题只发生在ng-repeat指令中?

我可以通过创建子范围并在需要时销毁(https://jsfiddle.net/yss4yskm/9/)来避免泄漏,但我不应该这样做。

angular.module('myApp', []).directive('myDirective', ['$compile', '$log', function ($compile, $log) { 
    var childScope; 

    function display(scopeId, x) { 
    $log.log('func called with', x, 'in scope', scopeId); 

    return x; 
    } 

    return { 
    scope: true, 
    link: function (scope, element) { 
     scope.array = [1, 2, 3]; 
     scope.display = display; 

     scope.$watch(function() { 
     return scope.abc; 
     }, function (newValue) { 
     element.empty(); 

     if (childScope) { 
      childScope.$destroy(); 
     } 

     element.append(angular.element('<div ng-repeat="item in array">{{display($id, item)}}</div>')); 

     childScope = scope.$new(); 

     $compile(element.contents())(childScope); 
     }); 
    } 
    }; 
}]); 

谢谢。

+0

你应该做'element.remove()'它也会删除范围.. –

+0

'element.remove()'不会删除范围。范围需要被明确销毁。 –

回答

0

回应自己。

查看角度来源。 element.empty()调用jQuery.empty(),除此之外没有其他任何东西!

删除DOM元素时,对角度范围的引用将被删除,但范围仍位于其父级的子范围的链接列表中。

因此需要子范围。

+0

'empty()'不会删除一个元素......它会删除它的内部html – charlietfl

+0

所以拥有'childScope'是唯一的解决方案吗? –