JavaScript 函数被事件侦听器多次调用,即使我引用了该函数

JavaScript function gets called multible times by event listener even though I reference the function

我每次创建 angular 控制器时都会添加一个事件侦听器。每次我离开此页面并返回时,都会添加一个新的事件侦听器,因为再次调用构造函数。

当这个事件被触发时,同一个事件被调用两次,如果我离开并回来,它被调用 3 次......等等。我只希望它总是被调用一次。

下面是添加事件监听器的代码,以及它调用的监听器函数: (仅供参考,我正在使用 TypeScript)

在构造函数中:

this.$window.addEventListener("message", this.processApi, false);

调用函数:

processApi = (e) => {
    this.processApiMessage(e.data);
};

我读到我应该调用对函数的引用而不是键入函数本身,因此两者都引用了同一个函数实例,但同一个事件侦听器被多次调用。

当我在 chrome 中使用开发人员工具并转到 EventListners 和消息部分时,每次点击构造函数时我都会看到一个新的 Window 元素。我可以通过开发人员工具删除每个 EventListers,但是当我这样做时似乎无法通过代码让它工作:

this.$window.removeEventListener("message", this.processApi, false);

我发现如果我刷新页面,所有事件侦听器都会清除,并且我在构造函数中创建的事件侦听器会正常工作。

我正在使用 angular,并使用 $location 服务导航到点击我的控制器的 url,因此快速修复是替换 $location.url( "url") 到 window.location.href("url")

这似乎有效,因为当我导航到页面时页面会刷新。我宁愿保留 $location 用于路由,即使 angular 构造函数被多次命中,我的事件监听器也只被命中一次。

当作用域为$destroyed时,您需要移除事件侦听器。因此,在控制器构造函数中,您需要注入 $scope 对象。在构造函数中,做这样的事情:

$scope.$on('$destroy', () => 
  $window.removeEventListener("message", this.processApi));

可以肯定的是,有多种创建控制器的方法。最常见的(特别是如果您使用的是 TypeScript)是为控制器创建一个 class。

我还会考虑将侦听器添加到 rootScope 而不是 $window,后者更像是 Angular 的处理方式。把它们放在一起,它看起来像这样:

class MyController {
  constructor($rootScope, $scope) {
    'ngInject';

    let unsubscriber = $rootScope.$on('message', this.processApi, false);    
    $scope.$on('$destroy', () => unsubscriber());  
  }
  ...
}