AngularJS – $ destroy是否删除事件监听器?
https://docs.angularjs.org/guide/directive
通过监听此事件,可以删除可能导致内存泄漏的事件侦听器。 注册到范围和元素的监听器在被销毁时会被自动清理,但是如果您在服务上注册监听器,或者在没有被删除的DOM节点上注册监听器,则必须自己清理它,或者你冒险引入内存泄漏。
最佳实践:指令应该自行清理。 您可以使用element.on('$ destroy',…)或作用域。$ on('$ destroy',…)在删除指令时运行清理函数。
题:
我有一个element.on "click", (event) ->
在我的指令里面:
- 当指令被破坏时,有没有对
element.on
内存引用来防止被垃圾收集? - Angular文档指出我应该使用一个处理程序来移除
$destroy
发送的事件上的事件侦听器。 我的印象是,destroy()
删除事件监听器,是不是这样的情况?
事件监听器
首先了解有两种“事件监听者”是很重要的:
-
通过
$on
注册的范围事件监听器:$scope.$on('anEvent', function (event, data) { ... });
-
通过例如
on
或bind
到元素的事件处理程序:element.on('click', function (event) { ... });
$范围。$摧毁()
当$scope.$destroy()
被执行时,它将删除在$ scope上通过$on
注册的所有监听器。
它不会删除DOM元素或第二种附加事件处理程序。
这意味着在指令的链接函数中手动调用$scope.$destroy()
将不会移除通过例如element.on
附加的处理程序,也不会移除DOM元素本身。
element.remove()
请注意, remove
是一个jqLite方法(如果在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元素的生命周期等,它当然会变得更复杂。