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

标签 angularjs angularjs-directive scope angularjs-scope

一直在文件馆和网上寻找答案,但没有真正找到答案,只是零零碎碎。似乎有很多建议的帖子,但没有一个有答案。

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

当我通过单击多个网格(状态)来更改状态(使用 ui.route 最新)时,网格指令的范围正在获取 $destroy 事件。处理程序正在工作。然而,作用域本身并没有得到 $destroy() 的调用。我在堆快照中看到指令的范围仍然通过 $$listeners 保留元素。此外,未设置 scope.$$destroyed。

但是,scope.prototype 被破坏了。因为它是,我什至不能从指令的 $on-$destroy 处理程序中调用 $scope.$destroy,因为原型(prototype)的 $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);
          });
        ...

将 scope.$$listeners = {} 设置为 $timeout 2000(让指令有时间在我的 on-$destroy 监听器中完成清理工作似乎有效,但使用内部组件感觉不对,有时它是没有足够长的时间让浏览器完成清理。这只是一种解决方法/kludge。

我也试过这个:

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

起初,我以为是因为我们在指令选项中使用了 scope: true ,因为 proto 范围似乎已经被破坏了。所以我写了a plunk to try that theory out .但是有了这个 plunk,指令的范围被正确地破坏并且没有对象被泄漏。实际上,非常令人惊讶。但是我没有使用我在第一个 plunk 中使用的相同 View 嵌套;但是我怀疑就是这样。当 View 发生变化时, Controller 范围仍然会被删除。我仍然有一个内部对象的观察者。所以我想我会看到类似的动态。但似乎 $destroy 确实是在该内部范围内调用的。

关于什么会阻止指令范围被调用 $destroy() 的任何想法? IT 似乎与范围有关:真正的一点,但我不能完全理解 Angular 的内部结构来说明原因。

先感谢您,

杰西

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

尽我所能,似乎正在发生的事情是元素的主要范围(而不是网格指令的半隔离范围)获得了 $destroy()d。但是,使用该作用域作为原型(prototype)的子作用域很可能会提前退出 $destroy 方法,因为 self.$$destroyed 是真的(原型(prototype)继承)。所以听众和观察者不会被清除。

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

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

所以,我写了一个服务,提供额外的清理,很容易注入(inject)到有问题的网格指令中。我有一个 plunk demo'ing 它,但由于我的声誉低,我不能将它发布到主要部分:)。现在,您可以随意切换网格,但当前网格将保留在堆上。

希望这可以帮助某人前进,

Ĵ

最佳答案

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

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

关于AngularJS:指令范围没有被调用 $destroy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26198501/

相关文章:

javascript - AngularJS 自定义指令双向绑定(bind)

javascript - 在 {} 和链接中为 Angular Directive(指令)定义隔离范围变量之间的区别

javascript - 嵌套的 Angular 指令在 `template` 和 `templateUrl` 上表现不同

javascript - 在这种情况下如何使变量全局可访问?

Javascript - "this"为空

angularjs - 在 UI bootstrap typeahead 中“显示更多结果”

javascript - ASP.NET 中的 SignalR 和 Angular,客户端没有得到响应

javascript - Angularjs 如何使用 ngView 处理内存管理?

c++ - 为什么这运行良好? (访问范围外变量的地址)

javascript - AngularJS ng-repeat 对象第一个属性上的键