Ответ 1
Слушатели событий
Прежде всего важно понять, что есть два типа "прослушивателей событий":
-
Слушатели событий Scope, зарегистрированные через
$on
:$scope.$on('anEvent', function (event, data) { ... });
-
Обработчики событий, прикрепленные к элементам через, например,
on
илиbind
:element.on('click', function (event) { ... });
$сфера. $Уничтожить()
Когда выполняется $scope.$destroy()
, он удалит всех слушателей, зарегистрированных через $on
, в этой области $scope.
Он будет не удалять элементы DOM или любые присоединенные обработчики событий второго рода.
Это означает, что вызов $scope.$destroy()
вручную из примера в функции директивной ссылки не удалит обработчик, прикрепленный через, например, element.on
, ни сам элемент DOM.
element.remove()
Обратите внимание, что remove
- это метод jqLite (или метод jQuery, если jQuery загружен до AngularjS) и недоступен для стандартного объекта элемента DOM.
Когда выполняется element.remove()
, этот элемент и все его дочерние элементы будут удалены из DOM вместе, все обработчики событий будут прикреплены, например, с помощью element.on
.
Он будет не уничтожать область $, связанную с элементом.
Чтобы сделать его более запутанным, также есть событие jQuery, называемое $destroy
. Иногда, когда вы работаете со сторонними библиотеками jQuery, которые удаляют элементы, или если вы удаляете их вручную, вам может потребоваться выполнить очистку, когда это произойдет:
element.on('$destroy', function () {
scope.$destroy();
});
Что делать, когда директива "уничтожена"
Это зависит от того, как "разрушена" директива.
В нормальном случае директива уничтожается, потому что ng-view
изменяет текущий вид. Когда это произойдет, директива ng-view
уничтожит связанную область $scope, разорвет все ссылки на ее родительскую область и вызовет remove()
для элемента.
Это означает, что если это представление содержит директиву с этим в своей функции ссылок, когда оно уничтожено ng-view
:
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
Оба прослушивателя событий будут удалены автоматически.
Однако важно отметить, что код внутри этих слушателей может по-прежнему вызывать утечку памяти, например, если вы достигли общего шаблона утечки памяти JS circular references
.
Даже в этом нормальном случае, когда директива будет уничтожена из-за изменения вида, есть вещи, которые могут понадобиться для ручной очистки.
Например, если вы зарегистрировали прослушиватель на $rootScope
:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
Это необходимо, так как $rootScope
никогда не уничтожается в течение всего срока службы приложения.
То же самое происходит, если вы используете другую реализацию pub/sub, которая автоматически не выполняет необходимую очистку при уничтожении области $или если ваша директива передает обратные вызовы сервисам.
Другая ситуация заключалась бы в отмене $interval
/$timeout
:
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
Если ваша директива прикрепляет обработчики событий к элементам, например за пределами текущего представления, вам также необходимо вручную их очистить:
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
Это были некоторые примеры того, что делать, когда директивы "уничтожены" с помощью Angular, например, ng-view
или ng-if
.
Если у вас есть пользовательские директивы, которые управляют жизненным циклом элементов DOM и т.д., это, конечно, будет более сложным.