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メソッドは、イベント リスナーの登録を解除するために呼び出すことができる関数を返します。後で使用するために、登録解除関数を変数として保存する必要があります: http://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$onvar cleanUpFunc = $scope.$on('yourevent', ...);のドキュメントを参照してください。$on

  • Angular でスコープがクリーンアップされる (つまり、コントローラーが破棄される) たびに、$destroyそのスコープでイベントが発生します。$scope$destroyイベントに登録して、cleanUpFuncそこから を呼び出すことができます。

これら 2 つの便利な機能を結び付けて、サブスクリプションを適切にクリーンアップできます。この例をまとめました: 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()$destroy、イベントのイベント リスナーがaction2@QuestionStatusController1サブスクライブ解除され、コントローラーがクリーンアップされたときにメモリ リークが発生しなくなります。

于 2013-09-17T17:55:41.420 に答える
43

$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 に答える