如何在JavaScript(或jQuery)中实现自定义广播事件?

我想实现一个可以“广播”的自定义事件,而不是发送到特定目标。 只有那些已将自己注册为此类事件的侦听器的元素才会收到它们。

我的想法如下。

首先,在代码的不同位置,会有表单的陈述

some_subscriber.on_signal( 'some_signal', some_handler ); 

我使用术语signal作为“广播事件”的简写。 在上面的表达式中, some_subscriber通过为它提供一个处理程序,将自身注册为这种信号的一种类型(称为’some_signal’)的监听器。

在代码的其他地方,会有表格的陈述

 publisher.signal_types[ 'some_signal' ].broadcast( event_data ); 

当执行这些语句时,会生成一个新事件并“ 广播 ”。 我的意思是,调用broadcast方法的代码没有关于它发出的信号的侦听器的直接信息。


我在这个jsFiddle中实现了这个想法的草图,主要是为了说明我在上面的文字中所描述的内容。 (它肯定不是生产级的,我不是特别相信它可以这么做。)

该实现的关键要素如下。 首先,发布者对象不会跟踪他们的订阅者 ,这可以在这种发布者的工厂方法的实现中看到,如下所示:

 function make_publisher ( signal_types ) { // ... var _ , signal = {} , ping = function ( type ) { signal[ type ].broadcast( ... ); } ; signal_types.forEach( function ( type ) { signal[ type ] = $.register_signal_type( type ); } ); return { signal_types: signal_types, ping: ping }; } 

此发布者对象仅公开两个项目:它广播的信号类型(在signal_types )和ping方法。 当调用ping方法时,发布者通过广播信号进行响应:

 signal[ type ].broadcast( ... ) 

此代码中无法看到此广播的最终收件人。

其次,在代码的其他地方,用户将自己注册为这些广播信号的监听器,就像这样

  $( some_selector ).on_signal( signal_type, some_handler ); 

注意:基本上不可能使用既小又实际的例子来说明该方案的基本原理。 这样做的原因是这个方案的优势在于它支持发布者代码和用户代码之间非常松散的耦合,这是一个在小例子中永远不需要的function。 相反,在一个小例子中,实现这种松散耦合的代码总是不必要地复杂化。 因此,重要的是要记住,这种明显的过度复杂性是上下文的人为因素。 松散耦合在大型项目中非常有用。 特别是,通过发布者/订阅者类型模式的松散耦合是MVC的基本特征之一。


我的问题是:是否有更好(或至少更标准)的方式来实现“广播”自定义事件的效果?

(我对基于jQuery的答案以及“纯JS”答案感兴趣。)


1这篇post的早期命运多变的版本几乎普遍不理解,而且(当然)是非常典型的向下投票。 除了一个例外,我所提出的所有评论都对post的前提提出了挑战,并且直接质疑我对事件驱动编程基础知识的掌握等等。我希望通过提供一个至少我的意思的工作示例它不会像我单独用文字描述的那样完全不可思议。 幸运的是,我之前发布的一条有用的评论告诉我函数jQuery.Callbacks 这确实是一个有用的提示; post中提到的草图实现基于jQuery.Callbacks

行。

所以我认为你可以做的是使用本机dispatchEventaddEventListener方法,并使用document作为发布订阅这些事件的唯一元素。 就像是:

 var myCustomEvent = new Event('someEvent'); document.dispatchEvent(myCustomEvent); ... document.addEventListener('someEvent', doSomething, false); 

要制作跨浏览器,您可以:

 var myCustomEvent = new Event('someEvent'); document.dispatchEvent(myCustomEvent); ... if (document.addEventListener) { document.addEventListener('someEvent', doSomething, false); } else { document.attachEvent('someEvent', doSomething); } 

您可以在此处和此处阅读有关此主题的更多信息 。 希望这可以帮助。

我的问题是:是否有更好(或至少更标准)的方式来实现“广播”自定义事件的效果?

不,在Javascript中没有更标准的发布/订阅方式。 它不是直接内置于语言或浏览器中,并且我不知道它没有平台标准。

您有几个选项(您似乎意识到其中大部分)将您自己的系统放在一起。

您可以选择一个特定的对象,例如document对象或window对象或您创建的新对象,并使用jQuery的.on().trigger()将该对象作为中央清算所,以拼凑发布/订阅状态模型。 如果你愿意,你甚至可以通过将它编码成几个实用程序函数来隐藏实际使用中该对象的存在。

或者,正如您似乎已经知道的那样,您可以使用jQuery.Callbacksfunction。 在jQuery doc中甚至还有发布/订阅示例代码。

或者,您可以找到提供某种传统发布/订阅模型的第三方库。

或者,您可以从头开始构建自己的实体,这实际上只涉及保留与特定事件关联的回调函数列表,因此当触发该事件时,您可以调用每个回调函数。

如果你来这里寻找jQuery这样做的方法,你可以去:

添加事件广播/发送代码:

句法:
$().trigger();

例:

 $.ajax({ ... complete: function () { // signal to registered listeners that event has occured $(document).trigger("build_complete"); ... } }); 

注册活动的监听器:

句法:
$().on(, function() {...});

例:

 $(document).on("build_complete", function () { NextTask.Init(); }); 

注意:这样做: $(document).build_complete(function() {...}); 导致错误: Uncaught TypeError: $(...).build_complete is not a function

Interesting Posts