Подтвердить что ты не робот

AngularJS: Directive Scope не получает $destroy, называемый

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

У меня есть сложная директива, которая использует scope: true. Это на самом деле версия последней версии ng-grid последней версии 2.x, которую я пытаюсь написать для кода очистки, поскольку это просто утечка памяти, как сумасшедшая, и наше приложение "застряло" с ней на данный момент. Здесь панель, которая демонстрирует проблему. Когда вы щелкаете по сетке и проверяете моментальные снимки кучи, вы увидите несколько "непривязанных" объектов ngGrid. Они только удерживаются слушателями в области действия директивы.

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

Однако scope.prototype IS уничтожен. И поскольку это так, я даже не могу назвать $scope. $Destroy из обработчика директивы $on-$ destroy, поскольку вызов proto $destroy() изменил определение $destroy to 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 в параметрах директивы, так как прото сфера, похоже, была уничтожена. Поэтому я написал планку, чтобы попробовать эту теорию. Но с этим плунгом область действия директивы должным образом уничтожается, и никакие объекты не просачиваются. На самом деле очень удивительно. Но я не использую одно и то же представление, которое у меня есть в первом plunk; однако я сомневаюсь в этом. Область управления по-прежнему стирается при изменении представлений. У меня все еще есть наблюдатель на внутреннем объекте. Поэтому я бы подумал, что увижу подобную динамику. Но похоже, что $destroy действительно вызывается в этой внутренней области.

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

Заранее спасибо,

Джесси


Обновление: ОК, я опубликую обновление для этой проблемы.

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

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

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

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

Надеюсь, это поможет кому-то идти вперед,

J

4b9b3361

Ответ 1

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

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