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

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. 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.

问题:

我有一个元素。点击,(事件)->在我的指令:

当指令被销毁时,是否存在对该元素的内存引用。如何防止它被垃圾收集? Angular文档指出,我应该使用一个处理程序来删除$destroy触发事件上的事件监听器。我的印象是destroy()删除事件监听器,不是这样吗?


当前回答

事件监听器

首先,重要的是要理解有两种“事件监听器”:

范围事件监听器通过$on注册: 美元的范围。$on('anEvent',函数(事件,数据){ ... }); 事件处理程序附加到元素,例如on或bind: 元素。On('点击',函数(事件){ ... });


范围。摧毁美元()

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

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

这意味着在指令的link函数中手动调用$scope.$destroy()不会删除通过for example元素附加的处理程序。on,也不是DOM元素本身。


element.remove ()

注意remove是一个jqLite方法(或者是一个jQuery方法,如果jQuery在AngularjS之前加载),并且在标准DOM元素对象中不可用。

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

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

更让人困惑的是,还有一个jQuery事件叫做$destroy。有时,当使用第三方jQuery库删除元素时,或者手动删除它们时,您可能需要执行清理:

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

当指令被“销毁”时该怎么做

这取决于指令是如何被“销毁”的。

正常情况下,由于ng-view改变了当前视图,指令被销毁。当这种情况发生时,ng-view指令将销毁相关的$作用域,切断对其父作用域的所有引用,并在元素上调用remove()。

这意味着,如果该视图在被ng-view销毁时,它的link函数中包含一个带有This的指令:

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

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

两个事件监听器都将被自动删除。

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

即使在这种由于视图改变而导致指令被破坏的正常情况下,也可能需要手动清理一些东西。

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

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

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

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

如果你正在使用另一个发布/订阅实现,当$作用域被破坏时,它不会自动执行必要的清理,或者如果你的指令向服务传递回调,情况也是一样的。

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

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

其他回答

事件监听器

首先,重要的是要理解有两种“事件监听器”:

范围事件监听器通过$on注册: 美元的范围。$on('anEvent',函数(事件,数据){ ... }); 事件处理程序附加到元素,例如on或bind: 元素。On('点击',函数(事件){ ... });


范围。摧毁美元()

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

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

这意味着在指令的link函数中手动调用$scope.$destroy()不会删除通过for example元素附加的处理程序。on,也不是DOM元素本身。


element.remove ()

注意remove是一个jqLite方法(或者是一个jQuery方法,如果jQuery在AngularjS之前加载),并且在标准DOM元素对象中不可用。

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

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

更让人困惑的是,还有一个jQuery事件叫做$destroy。有时,当使用第三方jQuery库删除元素时,或者手动删除它们时,您可能需要执行清理:

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

当指令被“销毁”时该怎么做

这取决于指令是如何被“销毁”的。

正常情况下,由于ng-view改变了当前视图,指令被销毁。当这种情况发生时,ng-view指令将销毁相关的$作用域,切断对其父作用域的所有引用,并在元素上调用remove()。

这意味着,如果该视图在被ng-view销毁时,它的link函数中包含一个带有This的指令:

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

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

两个事件监听器都将被自动删除。

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

即使在这种由于视图改变而导致指令被破坏的正常情况下,也可能需要手动清理一些东西。

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

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

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

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

如果你正在使用另一个发布/订阅实现,当$作用域被破坏时,它不会自动执行必要的清理,或者如果你的指令向服务传递回调,情况也是一样的。

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

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