Почему объекты не уничтожаются даже после запуска $destroy?
Я сделал директиву, которая при щелчке создает диалоговое окно, которое добавляется к телу с помощью jQuery. Проблема в том, что при закрытии диалога области видимости никогда не очищаются должным образом. Как показано на рисунке ниже 167 ChildScopes сохраняются. Что соответствует количеству элементов в диалоговом окне, которое включает директиву ng-repeat.
![enter image description here]()
Я попытался создать чрезвычайно простую версию сценария на Plnkr. К моему удивлению, области на самом деле удаляются на каждом близком расстоянии в Plnkr. Так что что-то, где-то в производстве, заставляет объекты оставаться в живых даже после того, как был вызван $destroy
.
link: ($scope, $element, $attr) ->
$element.on 'click', () ->
$scope.$apply () ->
child = $scope.$new()
template = """<span ng-controller="ListCtrl">...List dialog things...</span>"""
compiledTemplate = $compile(template)(child)
container = containers.createDialogContainer($element)
container.append(compiledTemplate)
#cleanup
$scope.closeWidget = () ->
container.trigger("container_close")
return
container.on "container_close", ()->
child.$apply () ->
child.$destroy()
return
Итак, вот мой вопрос:
Что может привести к тому, что область видимости останется в живых даже после того, как был вызван, вызван и запущен вызов $destroy?
По понятным причинам я не могу показать вам наш производственный код. Однако директива в Plnkr соответствует достаточному отладке.
Ответы
Ответ 1
В общем случае область (или любой другой объект JS) не может быть очищена GC, если она все еще доступна другому объекту JS.
На практике в проекте Angular, который также использует JQuery, это, скорее всего, вызвано:
- Angular служба, контроллер, область действия или какой-либо другой объект, все еще имеющий ссылку на объект области видимости
- ссылка на ваш объект все еще существует через элемент DOM, возможно, через прослушиватель событий. Элемент DOM может не быть GC-способным, потому что он все еще находится в кеше JQuery
Например, ваш пример создает утечку памяти.
Из вашего кода:
$scope.removeDialog = () ->
console.log "closing"
child.$destroy()
$('.listshell').remove()
return
Вы не устанавливаете child
в null
, поэтому $scope.removeDialog
все еще имеет доступ к объекту области, на который ссылается переменная child
. Следовательно, этот объект не может быть GC'ed.
NB: Мне кажется, что было бы более целесообразно поместить removeDialog
в область содержимого. Теперь ваш пример работает только потому, что область содержимого не изолирована.
Ответ 2
Функции закрытия могут привести к тому, что объект Activation останется активным даже после того, как область была "уничтожена". Например, у вас могут быть внутренние функции, которые все еще ссылаются на объекты переменных в функциях, объем которых вы пытаетесь уничтожить.
обнуление ссылочных переменных будет лучшим вариантом, а не удалением
Ответ 3
Единственное, что я могу придумать, это то, что если у вас где-то есть глобальная функция или функция вне контроллера или директивы, которая ссылается на метод внутри области действия для директивы, то он будет продолжать поддерживать эту область действия в течение всего времени приложение.