You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检查$rootScope.$on监听器是否已设置?避免重复添加无需辅助变量

How to Avoid Duplicate $rootScope.$on Listeners Without Auxiliary Variables

Great question! This is a super common pain point when working with AngularJS event listeners—repeated calls to add a listener lead to multiple instances firing when the event triggers. Here are a few approaches to solve this without relying on auxiliary tracking variables in your service:

AngularJS supports event namespaces, which let you target specific listeners for removal. Instead of adding a generic listener for messageFromSiteToHost, attach a unique namespace (like hostServiceListener) to it. Before adding the new listener, you can remove any existing ones with that namespace—this ensures only one listener is active at a time.

Here's how to implement it in your hostService.addListener method:

hostService.addListener = function(action) {
  // Remove any existing listener tied to our namespace
  $rootScope.off('messageFromSiteToHost.hostServiceListener');
  
  // Add the new listener with the namespace
  $rootScope.$on('messageFromSiteToHost.hostServiceListener', function(event, data) {
    action(data);
  });
};

This approach is clean, uses Angular's built-in features, and avoids extra variables. Even if addListener is called multiple times, each call replaces the existing listener instead of stacking new ones.

Solution 2: Check for Existing Listeners (Using Private API)

If you specifically want to check if the listener exists before adding it (rather than overwriting), you can access Angular's private $$listeners property on $rootScope. Important: This is a private API, so it might break in future Angular versions—use this cautiously.

Here's how you could check:

hostService.addListener = function(action) {
  // Check if any listeners exist for the target event
  const hasMatchingListener = $rootScope.$$listeners['messageFromSiteToHost']?.some(listener => {
    // This works only if `action` is a reusable function reference
    // Anonymous functions will fail this check (each is a unique reference)
    return listener.listener === action;
  });
  
  if (!hasMatchingListener) {
    $rootScope.$on('messageFromSiteToHost', action);
  }
};

A big caveat here: if action is an anonymous function created each time addListener is called, this check won't work. The namespace approach is far more reliable for that scenario.

Bonus: Single Deregistration Variable (If Flexible on "Auxiliary" Rule)

You mentioned avoiding auxiliary variables, but if you're open to a single, simple variable (not a complex tracking system), storing the deregistration function returned by $on is another solid pattern:

let deregisterListener;

hostService.addListener = function(action) {
  // Remove existing listener if it exists
  if (deregisterListener) {
    deregisterListener();
  }
  
  // Add new listener and save the deregistration function
  deregisterListener = $rootScope.$on('messageFromSiteToHost', function(event, data) {
    action(data);
  });
};

This uses Angular's native return value from $on, which is designed exactly for cleaning up listeners. It's a widely accepted pattern and keeps your code straightforward.


内容的提问来源于stack exchange,提问作者SoftTimur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:20:07