AngularJS – $ destroy是否删除事件监听器?

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

通过监听此事件,可以删除可能导致内存泄漏的事件侦听器。 注册到范围和元素的监听器在被销毁时会被自动清理,但是如果您在服务上注册监听器,或者在没有被删除的DOM节点上注册监听器,则必须自己清理它,或者你冒险引入内存泄漏。

最佳实践:指令应该自行清理。 您可以使用element.on('$ destroy',…)或作用域。$ on('$ destroy',…)在删除指令时运行清理函数。

题:

我有一个element.on "click", (event) ->在我的指令里面:

  1. 当指令被破坏时,有没有对element.on内存引用来防止被垃圾收集?
  2. Angular文档指出我应该使用一个处理程序来移除$destroy发送的事件上的事件侦听器。 我的印象是, destroy()删除事件监听器,是不是这样的情况?

事件监听器

首先了解有两种“事件监听者”是很重要的:

  1. 通过$on注册的范围事件监听器:

     $scope.$on('anEvent', function (event, data) { ... }); 
  2. 通过例如onbind到元素的事件处理程序:

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

$范围。$摧毁()

$scope.$destroy()被执行时,它将删除在$ scope上通过$on注册的所有监听器。

不会删除DOM元素或第二种附加事件处理程序。

这意味着在指令的链接函数中手动调用$scope.$destroy()将不会移除通过例如element.on附加的处理程序,也不会移除DOM元素本身。


element.remove()

请注意, remove是一个jqLit​​e方法(如果在AngularjS之前加载了jQuery,则是jQuery方法),并且在标准的DOM元素对象上不可用。

element.remove()被执行时,这个元素及其所有的子元素将被一起从DOM中删除,所有的事件处理程序将通过例如element.on

不会销毁与元素相关的$ scope。

为了让它更加混乱,还有一个名为$destroy的jQuery事件。 有时,在处理删除元素的第三方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永远不会被销毁。

如果您使用另一个发布/订阅实现,在$ scope被销毁时不会自动执行必要的清理,或者您的指令将callback传递给服务,也是如此。

另一种情况是取消$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

如果您有自定义指令来pipe理DOM元素的生命周期等,它当然会变得更复杂。