2014-10-05 2 views
12

Некоторое время искал в архивах и в сети ответы, но на самом деле не нашел их, просто бит и куски. Кажется, есть много предложенных сообщений, но никто из них не имеет ответа.

У меня есть сложная директива, которая использует область действия: true. На самом деле это последняя версия версии 2.x ng-grid, которую я пытаюсь написать для кода очистки, поскольку это просто утечка памяти, как сумасшедшая, и наше приложение «застряло» с ней на данный момент. Вот the plunk that demos the problem. Когда вы щелкаете по сетке и проверяете моментальные снимки кучи, вы увидите несколько «непривязанных» объектов ngGrid. Они только удерживаются слушателями в области действия директивы.

Когда я меняю состояния (используя последнюю версию ui.route), перейдя по нескольким сеткам (состояниям), область действия сетки получает событие $ destroy. Обработчик работает. Однако сама область не получает $ destroy(). Я вижу в снимке кучи, что область действия директивы все еще удерживает элементы через $$ слушателей. Кроме того, scope. $$ destroy не установлен.

Однако объем. прототипIS уничтожен. И потому, что это, я не могу даже назвать $ объема $ уничтожить от $ экранных $ уничтожить обработчика директивы, так как Проты $ уничтожить() вызов изменил определение $ уничтожить до Ноопа:.

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, кажется, работает, но он чувствует себя неловко с помощью внутренних функций, а иногда это . не достаточно долго для браузера, чтобы закончить очистку это просто обходным/ляп

Я также попытался это:.

Так что мешает моей директивы области действия п rom, получая $ destroy(), автоматически вызвал его?

Сначала я подумал, что это потому, что мы используем scope: true в параметрах директивы, поскольку прото сфера, похоже, была уничтожена. Поэтому я написал a plunk to try that theory out. Но с этим плунгом область действия директивы должным образом уничтожается, и никакие объекты не просачиваются. На самом деле очень удивительно. Но я не использую одно и то же представление, которое у меня есть в первом plunk; однако я сомневаюсь, что все. Область управления по-прежнему стирается при изменении представлений. У меня все еще есть наблюдатель на внутреннем объекте. Поэтому я бы подумал, что увижу подобную динамику. Но похоже, что $ destroy действительно призван к этой внутренней области.

Любые идеи о том, что помешало бы тому, чтобы объект директивы получал $ destroy()? Кажется, что это связано с масштабом: истинный бит, но я не могу достаточно затмить угловые внутренности, чтобы сказать, почему.

Спасибо заранее,

Джесси


Обновления: Хорошо, я выложу обновление к этому вопросу.

В меру моих возможностей, похоже, что происходит то, что основная область действия элемента (а не область полуизоляции для директивы grid) получает $ destroy() d. Тем не менее, дочерняя область, которая использует эту область действия в качестве прототипа, скорее всего, выйдет из метода $ destroy раньше, потому что self. $$ destroy является истинным (прототипное наследование). Поэтому слушателей и наблюдателей не очищают.

Возможно, я мог бы обновить директиву, чтобы полностью изолировать ее по охвату, но у меня нет времени, чтобы разобраться с последствиями этого.

Я также нашел, что это больше, чем просто $ destroy. Сама область $ имеет множество функций, определенных на ней директивой, которая формирует замыкание вокруг внутренних варов, которые содержат много памяти.

Итак, я написал службу, которая предоставляет дополнительную очистку, которая легко вводится в сомнительную директиву сетки. У меня есть демонстрация плунжера, но я не могу опубликовать его в главной части из-за моей низкой репутации :). Теперь вы можете переключать сетки на все, что вам нравится, и нет, но текущие сетки останутся в куче.

Надеется, что это помогает кто-то идти вперед,

J

+1

Вот ссылка на другой планшет, на котором показано упомянутое выше разрешение. http://plnkr.co/edit/r2uTKTJW2yJTbHx0kXYB – jessewolfe

+0

Привет, У меня была проблема, которая, как мне кажется, связана, вы нашли причину, почему $ destroy не вызывается в области? http://stackoverflow.com/questions/27467210/angular-directive-memory-leaks – Barnash

+0

Может быть интересно: в этой статье рассказывается о перерывах, которые могут произойти в цепочке $ destroy из-за плохих халдингов суб-областей (а именно: с помощью jquery) http: //www.bennadel.com/blog/2706-always-trigger-the-destroy-event-before-removing-elements-in-angularjs-directives.htm – Offirmo

ответ

1

Не знает, если это лучше подходят в качестве комментария или нет. Недавно я работал над большим проектом, в котором использовались ng-grid + angularjs, и у нас были все проблемы, с которыми вы столкнулись: утечка памяти. Мы обнаружили, что на самом деле не все было хорошо очищено, а места и часы просочились повсюду.

Мы попытались добавить пользовательскую логику, чтобы попытаться выполнить лучшую очистку, но это не помогло решить нашу проблему на 100%. Наши проблемы также были усугублены горизонтальной прокруткой + виртуализация на ng-сетке, поэтому было бы полезно также учитывать это (если я правильно помню, что они планировали исправить это в будущей версии).