AngularJS - $destroy удаляет прослушиватели событий?

https://docs.angularjs.org/guide/directive

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

Лучшая практика: директивы должны убирать за собой. Вы можете использовать element.on ('$destroy',...) или объем.$on ('$destroy',...) для запуска функции очистки при удалении директивы.

вопрос:

у меня есть element.on "click", (event) -> внутри моей директивы:

  1. когда директива уничтожена, есть ли какие-либо ссылки на память element.on, чтобы сохранить его от мусора?
  2. угловая документация заявляет, что I следует использовать обработчик для удаления прослушивателей событий на $destroy испускаемого событие. У меня сложилось впечатление, что destroy() удалены прослушиватели событий, не так ли?

1 ответов


прослушиватели событий

во-первых важно понимать, что есть два вида "слушатели":

  1. прослушиватели событий Scope зарегистрированы через $on:

    $scope.$on('anEvent', function (event, data) {
      ...
    });
    
  2. обработчики событий, прикрепленные к элементам, например on или bind:

    element.on('click', function (event) {
      ...
    });
    

$scope.$ destroy ()

, когда $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 директива уничтожит связанную область$, разорвет все ссылки на его родительскую область и вызов 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, которая не выполняется автоматически необходимая очистка при уничтожении $scope или если ваша директива передает обратные вызовы службам.

другой ситуацией было бы отменить $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);
});

это были некоторые примеры того, что делать, когда директивы "уничтожаются" угловым, например ng-view или ng-if.

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