AngularJS - czy $destroy usuwa słuchaczy zdarzeń?

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

Słuchając tego zdarzenia, możesz usunąć słuchacze zdarzeń, które mogą powodować wycieki pamięci. Słuchacze zarejestrowani w zakresach i elementach są automatycznie czyszczeni po ich zniszczeniu, ale jeśli zarejestrowałeś słuchacza w usłudze lub zarejestrowałeś słuchacza w węźle DOM, który nie jest usuwany, będziesz musiał to wyczyścić samodzielnie lub ryzykujesz spowodowanie wycieku pamięci.

Najlepsze Praktyki: Dyrektywy powinni posprzątać po sobie. Możesz użyć elementu.on ('$destroy',...) lub scope.$on ('$destroy',...), aby uruchomić funkcję czyszczenia po usunięciu dyrektywy.

Pytanie:

Mam element.on "click", (event) -> wewnątrz mojej dyrektywy:

  1. kiedy dyrektywa zostanie zniszczona, czy są jakieś odniesienia do pamięci element.on, aby zapobiec zbieraniu śmieci?
  2. dokumentacja kątowa stwierdza, że powinienem użyć funkcji obsługi do usunięcia detektorów zdarzeń na $destroy emitowanym zdarzeniu. Miałem wrażenie, że destroy() usunąłem słuchaczy zdarzeń, czy tak nie jest?
Author: tasseKATT, 2014-11-18

1 answers

Słuchacze zdarzeń

Po pierwsze, ważne jest, aby zrozumieć, że istnieją dwa rodzaje "słuchaczy zdarzeń":]}
  1. Scope event listeners registered via $on:

    $scope.$on('anEvent', function (event, data) {
      ...
    });
    
  2. Procedury obsługi zdarzeń dołączone do elementów za pomocą na przykład on lub bind:

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

$ scope.$destroy ()

Po wykonaniu $scope.$destroy() usunie wszystkie słuchacze zarejestrowane przez $on na tym $scope.

Będzie Nie Usuń elementy DOM lub dołączone procedury obsługi zdarzeń drugiego rodzaju.

Oznacza to, że ręczne wywołanie $scope.$destroy() z example w ramach funkcji link dyrektywy nie usunie obsługi dołączonej przez na przykład element.on, ani samego elementu DOM.


Element.remove ()

zauważ, że remove jest metodą jqLite (lub metodą jQuery, jeśli jQuery jest ładowane przed AngularjS) i nie jest dostępna w standardowym obiekcie elementu DOM.

Gdy element.remove() jest wywołanie tego elementu i wszystkie jego dzieci zostaną usunięte z drzewa DOM razem będą wszystkie procedury obsługi zdarzeń dołączone za pomocą na przykład element.on.

Spowoduje , a nie zniszczenie $scope powiązanego z elementem.

Aby było bardziej mylące, istnieje również zdarzenie jQuery o nazwie $destroy. Czasami podczas pracy z bibliotekami jQuery innych firm, które usuwają elementy, lub jeśli usuniesz je ręcznie, może być konieczne wyczyszczenie, gdy to dzieje się:

element.on('$destroy', function () {
  scope.$destroy();
});

Co zrobić, gdy dyrektywa zostanie "zniszczona"

To zależy od tego, jak dyrektywa zostanie "zniszczona".

Normalnym przypadkiem jest to, że dyrektywa jest niszczona, ponieważ ng-view zmienia bieżący widok. Gdy tak się stanie, dyrektywa ng-view zniszczy skojarzony z nią $scope, zerwie wszystkie odniesienia do jej nadrzędnego zakresu i wywoła remove() na elemencie.

Oznacza to, że jeśli ten widok zawiera dyrektywę z tym w swojej funkcji link, gdy ng-view:

scope.$on('anEvent', function () {
 ...
});

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

Oba słuchacze zdarzeń zostaną automatycznie usunięte.

Ważne jest jednak, aby pamiętać, że kod wewnątrz tych słuchaczy może nadal powodować wycieki pamięci, na przykład jeśli uzyskałeś wspólny wzór wycieku pamięci JScircular references.

Nawet w tym normalnym przypadku, gdy dyrektywa zostaje zniszczona z powodu zmiany widoku, mogą być rzeczy, które trzeba ręcznie wyczyścić.

Na przykład, jeśli zarejestrowałeś słuchacza na $rootScope:

var unregisterFn = $rootScope.$on('anEvent', function () {});

scope.$on('$destroy', unregisterFn);

Jest to potrzebne, ponieważ $rootScope nigdy nie jest niszczone podczas życia aplikacji.

To samo dzieje się, jeśli używasz innej implementacji pub/sub, która nie wykonuje automatycznie niezbędnego czyszczenia po zniszczeniu $scope lub jeśli twoja dyrektywa przekazuje wywołania zwrotne do usług.

Inną sytuacją byłoby anulowanie $interval/$timeout:

var promise = $interval(function () {}, 1000);

scope.$on('$destroy', function () {
  $interval.cancel(promise);
});

Jeśli twoja dyrektywa dołącza procedury obsługi zdarzeń do elementów na przykład poza obecnie Widok, trzeba ręcznie wyczyścić te, jak również:

var windowClick = function () {
   ...
};

angular.element(window).on('click', windowClick);

scope.$on('$destroy', function () {
  angular.element(window).off('click', windowClick);
});

Były to przykłady, co zrobić, gdy dyrektywy są "niszczone" przez Angular, na przykład przez ng-view lub ng-if.

Jeśli masz własne dyrektywy, które zarządzają cyklem życia elementów DOM itp. będzie to oczywiście bardziej złożone.

 421
Author: tasseKATT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-20 08:40:36