https://docs.angularjs.org/guide/directive
При прослушивании этого события вы можете удалить прослушиватели событий, которые могут вызвать утечку памяти. Слушатели, зарегистрированные в области и элементы, автоматически очищаются при их уничтожении, но если вы зарегистрировали прослушиватель в службе или зарегистрировали прослушиватель на DOM node, который не удаляется, вам придется его очистить или вы рискуете ввести утечку памяти.
Лучшая практика: директивы должны очищаться после себя. Вы можете использовать element.on('$ destroy',...) или scope. $On ('$ destroy',...) для запуска функции очистки при удалении директивы.
Вопрос:
У меня есть element.on "click", (event) ->
внутри моей директивы:
element.on
, чтобы сохранить ее от сбора мусора?
Документация $destroy
. У меня создалось впечатление, что destroy()
удалены прослушиватели событий, не так ли?Прежде всего важно понять, что есть два типа "прослушивателей событий":
Слушатели событий 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.
Обратите внимание, что 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 и т.д., это, конечно, будет более сложным.