如何销毁 AngularJS 中的 $emit 和 $broadcast 事件?

Leo*_*ban 5 javascript angularjs angularjs-directive angularjs-scope

Plnkr 示例构建:http ://plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview

按照此处的答案,我创建了一些$broadcast事件以允许 main$scope中的操作关闭 sub 中的弹出窗口$scopes。但是,我想确保我清理了所有事件,并且没有任何不该留下的东西。

我有一个 popover 指令,一旦 popover 被激活,我就会发出:

vs.$emit('popoverOpen');
Run Code Online (Sandbox Code Playgroud)

然后在主应用模块($rootScope)中,我在这里听:

vs.$on('popoverOpen',function(events,data) {

    // if 'popoverOpen' is heard, then activate this function
    // which on click $broadcasts out even 'bodyClick'
    // but also destroy the 'popoverOpen' event
    vs.bodyClick = function() {
        $rootScope.$broadcast('bodyClick');
        $rootScope.$$listenerCount.popoverOpen=[];
    };
});
Run Code Online (Sandbox Code Playgroud)

回到 popover 指令,这是我的bodyClick听众:

vs.$on('bodyClick', function() {
    vs.searchPopoverDisplay = false;
    $rootScope.$$listenerCount.bodyClick=[];
});
Run Code Online (Sandbox Code Playgroud)

^ 我也有代码试图终止该bodyClick事件,但无济于事:(

正如你可以看到下面,我已经删除bodyClick,并popoverOpen$$listenerCount(有一个在没有什么有$$listener对象。

然而,用户仍然可以访问vs.bodyClick()主应用程序 rootScope 中的函数,即使popoverOpen应该被删除。


所以在第一次加载时:

  • 如果用户在没有打开任何弹出窗口的情况下点击,bodyClick则永远不会被捕获/传输
  • 打开弹出框后,bodyClick处于活动状态
  • 如果用户点击正文,则发送该事件并关闭弹出窗口
  • 但是,现在即使没有打开弹出窗口,如果用户单击正文,则该bodyClick事件会不断发送出去

在此处输入图片说明

bodyClick在发送事件以关闭弹出窗口后,您将如何正确删除事件?


更新 我也试过这个(https://github.com/toddmotto/angularjs-styleguide#publish-and-subscribe-events),但在弹出窗口关闭并据称被销毁后,bodyClick事件仍然不断发送。

popoverDirective 函数仍然被调用:

vs.$on('bodyClick', function() {

    console.log('bodyClick received ...');
    console.log($rootScope.$$listener);
    console.log($rootScope.$$listenerCount);

    vs.searchPopoverDisplay = false;

    var unbind = $rootScope.$on('popoverOpen', []);
    vs.$on('$destroy', unbind);
    // $rootScope.$$listenerCount.bodyClick=[];
});
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

Ton*_*ony 3

关于你的 plunkr 的一些注意事项:

  1. 您的控制器都不会超出范围,因此它们都不会发出 $destroy.
  2. 您正在监听$destroy但试图发出destroy,这是不一样的。从侦听器中删除$,您将看到回调正在运行。
  3. 因为subController是销毁 main 的子级,mainController会销毁两者并停止按钮以及其他所有内容。此行为在此 plunkr中显示。

因此,为了获得伪$destroyping,我将其更改为仅监听destroy

然后,我没有调用 unbind (在这种情况下不起作用,因为我们实际上没有$destroy执行任何操作),而是简单地替换了该bodyClick函数,因为它绑定到了<body>.

$scope.$on('destroy', function() {
  $scope.bodyClick = angular.noop();
});
Run Code Online (Sandbox Code Playgroud)

这似乎达到了预期的效果。在这里更新了 Plunkr

更新:我发现了为什么它无限期地添加听众......!侦听destroy器位于按钮回调中。因此,每次按下按钮都会添加另一个回调。我将destroy侦听器移到了侦听器之外popover。不再有内存泄漏!