【问题标题】:Angular js subscribe multiple times and fire multiple eventsAngular js多次订阅并触发多个事件
【发布时间】:2017-01-03 07:01:48
【问题描述】:

我正在为一个应用程序工作,我想将 Angular js 与第三方 js 库进行通信。为此,我使用了使用中介 js 的 pubsub 方法。但是由于这个,当我订阅任何事件时,它会订阅多次,因此当我发布事件时,它会触发多次。

我使用了以下代码:

angular.module('app')
   .service('mediator', function() {
     var mediator = window.mediator || new Mediator();
     return mediator;
 });

// Main controller begins here
  angular.module('app').controller('MainController', MainController);
  MainController.$inject = ['mediator'];

  function MainController(mediator){
    var vm = this;
    vm.title = "This is main controller."

    vm.sendMessage = function(){
      mediator.publish('something', { data: 'Some data' });  
    }


  }


  // First page controller begins here
   angular.module('app').controller('FirstController', FirstController);
  FirstController.$inject = ['mediator'];

  function FirstController(mediator){
    var vm = this;

    console.log('Subscribed events for first controller.');

    var counter = 0;
    mediator.subscribe('something', function(data){ 
      console.log('Fired event for '+ counter.toString());
      counter = counter + 1;
    });

  }

这是为了更好地解释的 plunker: Plunkr

要测试这个 plunker:

  1. 运行 plunker。
  2. 打开开发者控制台。
  3. 点击首页
  4. 点击触发事件
  5. 点击第二页
  6. 点击首页
  7. 点击火灾事件

当您第二次导航到第一页时,它将再次订阅事件并触发两次。当您多次导航到第一页时,这将订阅多次。

如果我做错了什么,请告诉我。

【问题讨论】:

  • 您当前将在每次加载控制器时订阅,这将是每次您导航到页面时。这似乎是一个跟踪您是否订阅的简单案例,并使用if(!subscribed) 或类似名称。
  • 好吧,当你的控制器被销毁时,你并没有取消订阅。所以它一直被订阅。你不仅有多个控制台日志,还有一个很好的内存泄漏。
  • @JBNizet:您能告诉我们,如何使用调解器 js 取消订阅事件吗?
  • 请注意,角度范围具有本机事件机制。如果您使用标准的 $scope 机制来广播和收听事件,那么 Angular 会为您处理好这件事,因为控制器的 $scope 会随控制器一起销毁。
  • 仅仅因为您没有为 变量属性 主动注入 $scope 并不意味着它没有在 Angular 内部使用,或者您不能在需要时注入它,例如广播/发射。 “$scope 很糟糕”的口头禅通常被误解,并不完全正确。

标签: angularjs mediator


【解决方案1】:

您可以在控制器被销毁时取消订阅。

要使用中介器,首先需要保存订阅函数:

var sub = function(data){ 
  console.log('Fired event for '+ counter.toString());
  counter = counter + 1;
}
mediator.subscribe('something', sub);

然后您可以在控制器被移除时使用角度事件取消订阅通知:

$scope.$on("$destroy", function() {
    mediator.remove("something", sub);
});

无论何时使用此模式,都应考虑需要删除订阅的时刻,这不仅是出于重复原因,还可能导致内存泄漏。

别忘了你还需要注入 $scope (即使不将其用作模型的持有者,也可以将其用于注册事件侦听器):

angular.module('app').controller('FirstController', FirstController);
FirstController.$inject = ['mediator', '$scope'];

Plunkr 示例:https://plnkr.co/edit/CgYLLSxGF2Fww5vBB7PB

希望对你有帮助。

【讨论】:

  • 我不想在我的代码中使用 $scope。使用视图模型对象(vm)有什么办法吗?
  • 为什么不呢?我不确定是否有一种直接的方法可以在没有 $scope 的情况下将侦听器注册到 VM 事件,因为没有 $scope 就无法直接观察模型更改。同样,即使您使用推荐的控制器模式,仍然有一个由 angular 管理的范围。 $scope 非常适合用于上面提到的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 2019-08-27
  • 2019-03-06
  • 2019-09-22
相关资源
最近更新 更多