Ereignis-Listener
Zunächst ist es wichtig zu verstehen, dass es zwei Arten von "Ereignis-Listenern" gibt:
Scope Event Listener registriert über $on
:
$scope.$on('anEvent', function (event, data) {
...
});
Ereignishandler, die beispielsweise über on
oder an Elemente angehängt sind bind
:
element.on('click', function (event) {
...
});
$ scope. $ destroy ()
Wenn $scope.$destroy()
es ausgeführt wird, werden alle Listener entfernt, die über $on
diesen $ -Bereich registriert sind .
DOM-Elemente oder angehängte Ereignishandler der zweiten Art werden nicht entfernt.
Dies bedeutet, dass durch $scope.$destroy()
manuelles Aufrufen von Beispielen innerhalb der Verknüpfungsfunktion einer Direktive weder ein über beispielsweise angehängter Handler element.on
noch das DOM-Element selbst entfernt werden.
element.remove ()
Beachten Sie, dass dies remove
eine jqLite-Methode ist (oder eine jQuery-Methode, wenn jQuery vor AngularjS geladen wird) und für ein Standard-DOM-Elementobjekt nicht verfügbar ist.
Wenn element.remove()
dieses Element ausgeführt wird und alle seine untergeordneten Elemente zusammen aus dem DOM entfernt werden, werden beispielsweise alle Ereignishandler über angehängt element.on
.
Der dem Element zugeordnete $ scope wird nicht zerstört.
Um es verwirrender zu machen, gibt es auch ein jQuery-Ereignis namens $destroy
. Wenn Sie mit jQuery-Bibliotheken von Drittanbietern arbeiten, die Elemente entfernen, oder wenn Sie sie manuell entfernen, müssen Sie in diesem Fall möglicherweise eine Bereinigung durchführen:
element.on('$destroy', function () {
scope.$destroy();
});
Was tun, wenn eine Richtlinie "zerstört" wird?
Dies hängt davon ab, wie die Richtlinie "zerstört" wird.
Ein normaler Fall ist, dass eine Direktive zerstört wird, weil ng-view
sich die aktuelle Ansicht ändert. In diesem Fall zerstört die ng-view
Direktive den zugehörigen $ scope, trennt alle Verweise auf den übergeordneten Bereich und ruft remove()
das Element auf.
Dies bedeutet, dass wenn diese Ansicht eine Direktive mit dieser in ihrer Verknüpfungsfunktion enthält, wenn sie zerstört wird durch ng-view
:
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
Beide Ereignis-Listener werden automatisch entfernt.
Es ist jedoch wichtig zu beachten, dass der Code in diesen Listenern immer noch Speicherlecks verursachen kann, beispielsweise wenn Sie das übliche JS-Speicherleckmuster erreicht haben circular references
.
Selbst in diesem normalen Fall, in dem eine Direktive aufgrund einer Ansichtsänderung zerstört wird, müssen Sie möglicherweise einige Dinge manuell bereinigen.
Zum Beispiel, wenn Sie einen Listener registriert haben unter $rootScope
:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
Dies ist erforderlich, da $rootScope
es während der Lebensdauer der Anwendung niemals zerstört wird.
Das Gleiche gilt, wenn Sie eine andere Pub / Sub-Implementierung verwenden, die nicht automatisch die erforderliche Bereinigung durchführt, wenn der Bereich $ zerstört wird, oder wenn Ihre Direktive Rückrufe an Dienste weiterleitet.
Eine andere Situation wäre abzubrechen $interval
/ $timeout
:
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
Wenn Ihre Direktive Ereignishandler an Elemente anfügt, z. B. außerhalb der aktuellen Ansicht, müssen Sie diese ebenfalls manuell bereinigen:
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
Dies waren einige Beispiele dafür, was zu tun ist, wenn Anweisungen von Angular "zerstört" werden, beispielsweise von ng-view
oder ng-if
.
Wenn Sie benutzerdefinierte Anweisungen haben, die den Lebenszyklus von DOM-Elementen usw. verwalten, wird dies natürlich komplexer.