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

jes*_*lfe 12 scope angularjs angularjs-directive angularjs-scope

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

我有一个复杂的指令,使用范围:true.它实际上是我正在尝试编写清理代码的ng-grid最新2.x版本,因为它只是像疯了一样泄漏内存,而我们的应用程序暂时"卡住"它.这是演示问题的插件.当您单击网格并随后检查堆快照时,您将看到几个"未附加的"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);
          });
        ...
Run Code Online (Sandbox Code Playgroud)

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

我也试过这个:

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

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

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

先感谢您,

杰西


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

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

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

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

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

希望这有助于前进的人,

Ĵ

小智 1

不知道这是否更适合作为评论。我最近从事一个使用 ng-grid + angularjs 的大型项目,我们遇到了您遇到的所有问题:大量内存泄漏。我们发现,确实并不是所有东西都得到了很好的清洁,瞄准镜和手表到处都是泄漏的。

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