AngularJS:指令范围没有调用$ destroy

时间:2014-10-05 00:34:28

标签: angularjs angularjs-directive scope angularjs-scope

在档案馆和网上寻找一段时间寻找答案,但并没有真正找到一个,只是点点滴滴。似乎有很多建议的帖子,但没有一个有答案。

我有一个使用范围的复杂指令:true。它实际上是我正在尝试编写清理代码的ng-grid最新2.x版本,因为它只是像疯了一样泄漏内存,而我们的应用程序暂时“卡住”它。这是the plunk that demos the problem。当您单击网格并随后检查堆快照时,您将看到几个“未附加的”ngGrid对象。这些仅由听众在指令的范围内压制。

当我通过单击多个网格(状态)更改状态(使用ui.route最新)时,网格指令的范围是获取$ destroy事件。处理程序正在运行。但是,范围本身并没有调用$ destroy()。我在堆快照中看到指令的范围仍然通过$$监听器保留元素。此外,未设置范围。$$销毁。

但是,范围。原型 IS 已销毁。因为它是,我甚至不能从指令的$ on- $ destroy处理程序调用$ scope。$ destroy,因为proto的$ destroy()调用将$ destroy的定义更改为noop:

ngGridDirectives.directive('ngGrid', ['$compile', '$filter', '$templateCache', '$sortService', '$domUtilityService', '$utilityService', '$timeout', '$parse', '$http', '$q',
    function($compile, $filter, $templateCache, sortService, domUtilityService, $utils, $timeout, $parse, $http, $q) {
  var ngGridDirective = {
    scope: true,
    compile: function() {
      return {
        pre: function($scope, iElement, iAttrs) {
          $(iElement).on('$destroy', function cleanupElementNgGrid() {
              $timeout(function() {
                $scope.$destroy();
                $scope.destroyedByForce = true;
                console.log("I destroyed it.");
              },4000);
          });
        ...

设置范围。$$ listeners = {},$ timeout为2000(为指令完成清理我的on- $ destroy监听器的时间似乎有效,但是对内部进行挖掘感觉不对,有时它不足以让浏览器完成清理工作。它只是一个解决方案/ kludge。

我也试过这个:

那么是什么阻止我的指令范围自动调用$ destroy()呢?

起初,我认为这是因为我们在指令选项中使用scope:true,因为proto范围似乎已被破坏。所以我写了a plunk to try that theory out。但是使用这个插件,指令的范围被正确销毁并且没有对象泄露。实际上非常令人惊讶。但是我没有在第一次使用中使用相同的视图嵌套;但我怀疑是这样的。视图更改时,控制器范围仍会被擦除。我仍然在内部对象上有一个观察者。所以我认为我会看到类似的动态。但看起来$ destroy实际上是在内部范围内调用的。

关于什么会阻止指令范围调用$ destroy()的想法呢?它似乎与范围有关:真正的位,但我不能完全理解角度内部足以说出原因。

提前谢谢你,

杰西


更新:好的,我会发布此问题的更新。

尽我所能,似乎正在发生的事情是元素的主要范围(不是网格指令的半隔离范围)得到$ destroy()d。但是,使用该范围作为原型的子范围很可能很早就会淘汰$ destroy方法,因为self。$$被破坏是真的(原型继承)。所以听众和观察者都不会被清除。

我可能会更新指令以在范围内完全隔离,但我没有时间理清它的含义。

我还发现它不仅仅是$ destroy。 $ scope本身有很多函数由指令定义,它在内部变量周围形成闭包,占用大量内存。

所以,我写了一个服务,提供额外的清理,很容易注入有问题的网格指令。我有一个插件演示它,但由于我的声誉很低,我无法将它发布在主要部分:)。现在,你可以随心所欲地切换网格,除了当前的网格之外没有其他网格将保留在堆上。

希望这有助于某些人前进,

Ĵ

1 个答案:

答案 0 :(得分:1)

不知道这是否更适合作为评论。我最近参与了一个使用ng-grid + angularjs的大型项目,我们遇到了你遇到的所有问题:内存泄漏问题。我们发现确实并非所有东西都被很好地清理干净,并且范围和手表都被泄露到了整个地方。

我们尝试添加一些自定义逻辑来尝试进行更好的清理,但它并没有100%解决我们的问题。我们的问题也通过ng-grid上的水平滚动+虚拟化加以强调,因此记住这一点也很有用(如果我没记错的话,他们计划在将来的版本中修复它)。