我希望实现一个自定义事件,可以“广播”,而不是发送到特定的目标。只有那些已经将自己注册为此类事件侦听器的元素将收到它们。
我考虑的方案如下。
首先,在代码的各个位置,会有以下形式的语句
some_subscriber.on_signal( 'some_signal', some_handler );
我使用术语signal
作为“广播事件”的简称。在上面的表达式中,some_subscriber
通过提供一个处理程序将自己注册为这些信号中的一种类型(称为“some_signal”)的监听器。
在代码的其他地方将会有形如以下语句的代码:
publisher.signal_types[ 'some_signal' ].broadcast( event_data );
当执行这样的语句时,会生成一个新的事件并进行“广播”。我指的是调用方法的代码没有直接关于其所发出信号的侦听器的信息。
我在这个 jsFiddle中实现了这个想法的草图,主要是为了说明我上面描述的内容1。(它肯定不是生产级别的,而且我并不特别有信心能够实现。)
此实现的关键元素如下所示。首先,发布者对象不会跟踪其订阅者,可以在下面所示的创建此类发布者的工厂方法的实现中看到:
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 );
注意:基本上不可能用一个既小又现实的例子来说明此方案的原理。这是因为该方案的优势在于它支持发布者代码和订阅者代码之间非常松散的耦合,而这在一个小的示例中从未必要。相反,在一个小的示例中,实现这样的松散耦合的代码无论如何都会显得不必要地复杂。因此,重要的是要记住,这种明显的过多复杂性是环境的产物。松散的耦合在更大的项目中非常有用。特别是通过发布者/订阅者类型模式的松散耦合是MVC的基本特征之一。
我的问题是:有没有更好(或至少更标准)的方法来实现“广播”自定义事件的效果?
(我对基于jQuery和“纯JS”的答案都很感兴趣。)
1本文的早期版本备受普遍的不理解和(当然)典型的投票否定。除了一个例外,所有的评论都质疑了本文的前提,并直接质疑了我的事件驱动编程的基础等等。我希望通过展示一个工作示例来说明我所说的至少不会像我仅用文字描述时那样难以想象。幸运的是,在早期帖子中我得到的唯一有帮助的评论告诉我函数jQuery.Callbacks
。这确实是一个有用的提示;本文提到的简要实现是基于jQuery.Callbacks
。
dispatchEvent
和addEventListener
方法,特别是当两者都可以在document
对象上使用时,因此,唯一的依赖关系是全局document
对象,用于分别进行广播和监听**。我也很想知道,如果你知道它们,你注意到了什么缺点,促使你提出自己的解决方案。谢谢。 - Tahir Ahmeddocument.dispatchEvent()
和document.addEventListener
应该可以提供这种功能。这样,你的document
对象就成为了所有事件的通道,一个代理。而且,你也可以使用方法来跨浏览器地使用它们。 - Tahir Ahmed