AngularJS - $destroy 会删除事件侦听器吗? [英] AngularJS - Does $destroy remove event listeners?

查看:34
本文介绍了AngularJS - $destroy 会删除事件侦听器吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

通过侦听此事件,您可以移除可能导致内存泄漏的事件侦听器.注册到作用域和元素的侦听器在销毁时会自动清理,但是如果您在服务上注册了侦听器,或者在未被删除的 DOM 节点上注册了侦听器,则必须自己清理或可能会导致内存泄漏.

By listening to this event, you can remove event listeners that might cause memory leaks. Listeners registered to scopes and elements are automatically cleaned up when they are destroyed, but if you registered a listener on a service, or registered a listener on a DOM node that isn't being deleted, you'll have to clean it up yourself or you risk introducing a memory leak.

最佳实践:指令应自行清理.您可以使用 element.on('$destroy', ...) 或 scope.$on('$destroy', ...) 在指令被移除时运行清理函数.

Best Practice: Directives should clean up after themselves. You can use element.on('$destroy', ...) or scope.$on('$destroy', ...) to run a clean-up function when the directive is removed.

问题:

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

  1. 当指令被销毁时,是否有任何对 element.on 的内存引用以防止它被垃圾收集?
  2. Angular 文档指出,我应该使用处理程序来移除 $destroy 发出的事件上的事件侦听器.我的印象是 destroy() 删除了事件侦听器,不是这样吗?
  1. When the directive is destroyed, are there any memory references to the element.on to keep it from being garbage collected?
  2. Angular documentation states that I should use a handler to remove event listeners on the $destroy emitted event. I was under the impression that destroy() removed event listeners, is this not the case?

推荐答案

事件监听器

首先,重要的是要了解有两种事件侦听器":

Event listeners

First off it's important to understand that there are two kinds of "event listeners":

  1. 通过 $on 注册的作用域事件监听器:

  1. Scope event listeners registered via $on:

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

  • 通过例如 onbind 附加到元素的事件处理程序:

  • Event handlers attached to elements via for example on or bind:

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

  • <小时>

    $scope.$destroy()

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


    $scope.$destroy()

    When $scope.$destroy() is executed it will remove all listeners registered via $on on that $scope.

    不会删除 DOM 元素或任何附加的第二类事件处理程序.

    It will not remove DOM elements or any attached event handlers of the second kind.

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

    This means that calling $scope.$destroy() manually from example within a directive's link function will not remove a handler attached via for example element.on, nor the DOM element itself.

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

    Note that remove is a jqLite method (or a jQuery method if jQuery is loaded before AngularjS) and is not available on a standard DOM Element Object.

    当执行 element.remove() 时,该元素及其所有子元素将从 DOM 中删除,所有事件处理程序都会通过例如 element.on 附加.

    When element.remove() is executed that element and all of its children will be removed from the DOM together will all event handlers attached via for example element.on.

    不会破坏与元素关联的 $scope.

    It will not destroy the $scope associated with the element.

    为了让它更加混乱,还有一个名为 $destroy 的 jQuery 事件.有时在使用删除元素的第三方 jQuery 库时,或者如果您手动删除它们,您可能需要在发生这种情况时执行清理:

    To make it more confusing there is also a jQuery event called $destroy. Sometimes when working with third-party jQuery libraries that remove elements, or if you remove them manually, you might need to perform clean up when that happens:

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

    <小时>

    当指令被销毁"时该怎么办

    这取决于指令是如何销毁"的.


    What to do when a directive is "destroyed"

    This depends on how the directive is "destroyed".

    正常情况是指令被销毁,因为 ng-view 更改了当前视图.发生这种情况时,ng-view 指令将销毁关联的 $scope,切断对其父作用域的所有引用,并在元素上调用 remove().

    A normal case is that a directive is destroyed because ng-view changes the current view. When this happens the ng-view directive will destroy the associated $scope, sever all the references to its parent scope and call remove() on the element.

    这意味着如果该视图在其被 ng-view 销毁时在其链接函数中包含带有 this 的指令:

    This means that if that view contains a directive with this in its link function when it's destroyed by ng-view:

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

    两个事件侦听器都将被自动删除.

    Both event listeners will be removed automatically.

    但是,需要注意的是,这些侦听器内部的代码仍然会导致内存泄漏,例如,如果您已经实现了常见的 JS 内存泄漏模式循环引用.

    However, it's important to note that the code inside these listeners can still cause memory leaks, for example if you have achieved the common JS memory leak pattern circular references.

    即使在指令因视图更改而被破坏的正常情况下,您也可能需要手动清理某些内容.

    Even in this normal case of a directive getting destroyed due to a view changing there are things you might need to manually clean up.

    例如,如果您在 $rootScope 上注册了一个监听器:

    For example if you have registered a listener on $rootScope:

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

    这是必需的,因为 $rootScope 在应用程序的生命周期内永远不会被销毁.

    This is needed since $rootScope is never destroyed during the lifetime of the application.

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

    The same goes if you are using another pub/sub implementation that doesn't automatically perform the necessary cleanup when the $scope is destroyed, or if your directive passes callbacks to services.

    另一种情况是取消$interval/$timeout:

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

    如果您的指令将事件处理程序附加到元素,例如当前视图之外的元素,您也需要手动清理它们:

    If your directive attaches event handlers to elements for example outside the current view, you need to manually clean those up as well:

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

    这些是当指令被 Angular破坏"时该怎么做的一些例子,例如 ng-viewng-if.

    These were some examples of what to do when directives are "destroyed" by Angular, for example by ng-view or ng-if.

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

    If you have custom directives that manage the lifecycle of DOM elements etc. it will of course get more complex.

    这篇关于AngularJS - $destroy 会删除事件侦听器吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆