繁体   English   中英

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

[英]How are custom broadcast events implemented in JavaScript (or jQuery)?

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

我的想法如下。

首先,在代码的各个地方,都会有这样的语句

some_subscriber.on_signal( 'some_signal', some_handler );

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

在代码的其他地方,会有形式的语句

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

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


我在这个 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

好的。

所以我认为你可以做的是使用原生的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.Callbacks功能。 jQuery 文档中甚至还有发布/订阅示例代码。

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

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

如果你来这里是为了寻找jQuery方式来做这件事,那么你去吧:

添加事件广播/调度代码:

句法:
$(<element-name>).trigger(<event-name>); .

例子:

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

为事件注册一个监听器:

句法:
$(<element-name>).on(<event-name>, function() {...});

例子:

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

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

我知道这在 2015 年已被标记为已回答——但一个优雅而简单的解决方案可能是使用Redux

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM