68

我有以下内容:

angular.module('test')
    .controller('QuestionsStatusController1',
    ['$rootScope', '$scope', '$resource', '$state',
    function ($rootScope, $scope, $resource, $state) {

        $scope.action2 = function() {
            $rootScope.$broadcast('action2@QuestionStatusController1');
        }

    }]);

angular.module('test')
   .controller('QuestionsStatusController2',
   ['$rootScope', '$scope', '$resource', '$state',
   function ($rootScope, $scope, $resource, $state) {

    $rootScope.$on('action2@QuestionStatusController1', function {
         //write your listener here
    })

   }]);

我的理解是我需要取消注册监听事件。有人可以告诉我如何编码/做到这一点吗?

4

4 回答 4

152

如果您不取消注册该事件,则会发生内存泄漏,因为您传递给的函数$on不会被清理(因为对它的引用仍然存在)。更重要的是,在其作用域内引用的任何变量也将被泄露。如果您的控制器在应用程序中被多次创建/销毁,这将导致您的函数被多次调用。幸运的是,AngularJS 提供了一些有用的方法来避免内存泄漏和不需要的行为:

  • $on方法返回一个函数,可以调用该函数来取消注册事件侦听器。您需要将注销函数保存为变量以供以后使用:var cleanUpFunc = $scope.$on('yourevent', ...);请参阅文档$onhttp ://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$on

  • 每当在 Angular 中清理范围(即控制器被销毁)$destroy时,就会在该范围上触发一个事件。您可以注册到$scope'$destroy事件并从中调用您的事件cleanUpFunc

您可以将这两个有用的东西联系在一起,以正确清理您的订阅。我整理了一个例子:http ://plnkr.co/edit/HGK9W0VJGip6fhYQQBCg?p=preview 。如果您注释掉该行cleanUpFunc();,然后按几次切换和执行按钮,您会注意到我们的事件处理程序被多次调用,这并不是真正需要的。

现在,毕竟,要使您的特定情况正常运行,只需将您的代码更改QuestionsStatusController2为以下内容:

angular.module('test')
   .controller('QuestionsStatusController2',
   ['$rootScope', '$scope', '$resource', '$state',
   function ($rootScope, $scope, $resource, $state) {

    var cleanUpFunc = $rootScope.$on('action2@QuestionStatusController1', function {
         //write your listener here
    });

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

   }]);

通过调用cleanUpFunc()in $destroy,您的事件监听器action2@QuestionStatusController1将被取消订阅,并且当您的控制器被清理时您将不再泄漏内存。

于 2013-09-17T17:55:41.420 回答
43

在 local 上注册监听器$scope,而不是在上$rootScope,当控制器被移除时,监听器将被自动销毁。

所以要发布

// EXAMPLE PUBLISHER
angular.module('test').controller('CtrlPublish', ['$rootScope', '$scope',
function ($rootScope, $scope) {

  $rootScope.$broadcast('topic', 'message');

}]);

并订阅

// EXAMPLE SUBSCRIBER
angular.module('test').controller('ctrlSubscribe', ['$scope',
function ($scope) {

  $scope.$on('topic', function (event, arg) { 
    $scope.receiver = 'got your ' + arg;
  });

}]);

普朗克

于 2014-09-26T13:27:48.683 回答
15

这是关于注销逻辑的源代码。你可以做:

$rootScope.$on('action2@QuestionStatusController1', function () {
    $rootScope.$$listeners['action2@QuestionStatusController1'] = [];
})

或调用从返回的注销函数$on()

var deregistration = $rootScope.$on('action2@QuestionStatusController1', function () {
    deregistration();
})
于 2013-09-17T17:49:19.860 回答
0
$scope.$on('saveCancelLeadInfo', function (event, args) {

        if ($scope.$$listenerCount["saveCancelLeadInfo"] > 1) {

            $scope.$$listenerCount["saveCancelLeadInfo"] = 0;

        } });
于 2016-05-30T11:42:15.193 回答