自定义广播事件是如何在 JavaScript(或 jQuery)中实现的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31217465/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are custom broadcast events implemented in JavaScript (or jQuery)?
提问by kjo
I want to implement a custom event that can be "broadcast", rather than sent to specific targets. Only those elements that have registered themselves as listeners for such events will receive them.
我想实现一个可以“广播”的自定义事件,而不是发送到特定目标。只有将自己注册为此类事件侦听器的元素才会接收它们。
What I have in mind would look as follows.
我的想法如下。
First, in various places of the code, there would be statements of the form
首先,在代码的各个地方,都会有这样的语句
some_subscriber.on_signal( 'some_signal', some_handler );
I'm using the term signal
as shorthand for "broadcast event". In the expression above, some_subscriber
registers itself as a listener of one type (called 'some_signal') of such signals, by providing a handler for it.
我使用该术语signal
作为“广播事件”的简写。在上面的表达式中some_subscriber
,通过为其提供处理程序,将自己注册为此类信号的一种类型(称为“some_signal”)的侦听器。
Elsewhere in the code, there would be statements of the form
在代码的其他地方,会有以下形式的语句
publisher.signal_types[ 'some_signal' ].broadcast( event_data );
When statements like these get executed, a new event is generated and "broadcast". By this I mean that the code that calls the broadcast
method has no direct information about the listeners for the signal it is issuing.
当执行这些语句时,会生成一个新事件并“广播”。我的意思是,调用该broadcast
方法的代码没有关于它发出的信号的侦听器的直接信息。
I have implemented a sketch of this idea in this jsFiddle, mostly in order to illustrate what I described in words above1. (It's certainly not production-grade, and I'm not particularly confident that it could be made so.)
我在这个 jsFiddle 中实现了这个想法的草图,主要是为了说明我在上面的文字中描述的内容1。(它当然不是生产级的,我并不是特别有信心可以做到这一点。)
The key elements of this implementation are the following. First, publisher objects do not keep track of their subscribers, as can be seen in the implementation of a factory method for such a publisher, shown below:
此实施的关键要素如下。首先,发布者对象不跟踪他们的订阅者,正如在为这样的发布者实现工厂方法中可以看到的,如下所示:
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 };
}
This publisher object exposes only two items: the types of signals it broadcasts (in signal_types
), and a ping
method. When its ping
method is invoked, the publisher responds by broadcastinga signal:
这个发布者对象只公开两个项目:它广播的信号类型(in signal_types
)和一个ping
方法。当它的ping
方法被调用时,发布者通过广播一个信号来响应:
signal[ type ].broadcast( ... )
The ultimate recipients of this broadcast are nowhere to be seen in this code.
在此代码中无处可见此广播的最终接收者。
Second, elsewhere in the code, subscribers register themselves as listeners of these broadcast signals, like so
其次,在代码的其他地方,订阅者将自己注册为这些广播信号的听众,就像这样
$( some_selector ).on_signal( signal_type, some_handler );
Note:It is basically impossible to illustrate the rationale for this scheme using an example that is both small and realistic. The reason for this is that the strength of this scheme is that it supports very loose coupling between the publisher code and subscriber code, and this is a feature that is never necessary in a small example. On the contrary, in a small example, code that implements such loose coupling invariably comes across as unnecessarily complex. It is therefore important to keep in mind that this apparent excess complexity is an artifact of the context. Loose coupling is very useful in larger projects. In particular, loose coupling via a publisher/subscriber-type pattern is one of the essential features of MVC.
注意:基本上不可能用一个既小又现实的例子来说明这个方案的基本原理。这样做的原因是这个方案的优势在于它支持发布者代码和订阅者代码之间非常松散的耦合,而这是一个小例子中永远不需要的特性。相反,在一个小例子中,实现这种松散耦合的代码总是显得过于复杂。因此,重要的是要记住,这种明显的过度复杂性是上下文的产物。松散耦合在大型项目中非常有用。特别是,通过发布者/订阅者类型模式的松散耦合是 MVC 的基本特征之一。
My question is:is there a better (or at least more standard) way to achieve this effect of "broadcasting" custom events?
我的问题是:有没有更好(或至少更标准)的方法来实现“广播”自定义事件的这种效果?
(I'm interested in both jQuery-based answers as well as "pure JS" ones.)
(我对基于 jQuery 的答案以及“纯 JS”的答案都感兴趣。)
1An earlier, ill-fated version of this post was met with almost universal incomprehension, and (of course) the all-too-typical down-voting. With one exception, all the comments I got challenged the very premises of the post, and one directly questioned my grasp of the basics of event-driven programming, etc. I'm hoping that by presenting a working example of what I mean at least it won't come across as utterly inconceivable as it did when I described it in words alone. Luckily, the one helpful comment I did get on that earlier post informed me of the function jQuery.Callbacks
. This was indeed a useful tip; the sketch implementation mentioned in the post is based on jQuery.Callbacks
.
1这篇文章较早的、命运多舛的版本几乎遭到了普遍的不理解,并且(当然)也遭到了非常典型的否决。除了一个例外,我收到的所有评论都挑战了这篇文章的前提,一个直接质疑我对事件驱动编程等基础知识的掌握。我希望通过展示一个工作示例来表达我的意思它不会像我单独用文字描述时那样完全不可思议。幸运的是,我在之前的帖子中得到的一条有用评论告诉了我这个功能jQuery.Callbacks
。这确实是一个有用的提示;帖子中提到的草图实现基于jQuery.Callbacks
.
回答by Tahir Ahmed
All right.
好的。
So I think what you can do is use the native dispatchEvent
and addEventListener
methods and use document
as the only element for both publishingand subscribingto those events. Something like:
所以我认为你可以做的是使用本机dispatchEvent
和addEventListener
方法,并将其document
用作发布和订阅这些事件的唯一元素。就像是:
var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
document.addEventListener('someEvent', doSomething, false);
And to make cross-browser, you could:
要跨浏览器,您可以:
var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
if (document.addEventListener) {
document.addEventListener('someEvent', doSomething, false);
} else {
document.attachEvent('someEvent', doSomething);
}
You can read more on the subject hereand here. Hope this helps.
回答by jfriend00
My question is: is there a better (or at least more standard) way to achieve this effect of "broadcasting" custom events?
我的问题是:有没有更好(或至少更标准)的方法来实现“广播”自定义事件的这种效果?
No, there is not a more standard way of doing publish/subscribe in Javascript. It is not directly built into the language or the browser and there are no platform standards for it that I'm aware of.
不,在 Javascript 中没有更标准的发布/订阅方式。它没有直接内置到语言或浏览器中,而且我知道没有针对它的平台标准。
You have several options (most of which you seem aware of) to put your own system together.
您有多种选择(其中大部分您似乎都知道)将您自己的系统组合在一起。
You could pick a specific object such as the document
object or the window
object or a new object you create and use jQuery's .on()
and .trigger()
with that object as a central clearing house to cobble together a publish/subscribe-like model. You could even hide the existence of that object from your actual use by just coding it into a few utility functions if you want.
您可以选择一个特定的对象,例如您创建的document
对象或window
对象或新对象,并使用 jQuery.on()
和.trigger()
该对象作为中央票据交换所,以拼凑出类似发布/订阅的模型。如果您愿意,您甚至可以通过将其编码为一些实用程序函数来隐藏该对象的存在,使其不被实际使用。
Or, as you seem to already know, you could use the jQuery.Callbacks
functionality. There's even publish/subscribe sample code in the jQuery doc.
或者,正如您似乎已经知道的那样,您可以使用该jQuery.Callbacks
功能。jQuery 文档中甚至还有发布/订阅示例代码。
Or, you can find a third party library that offers a somewhat traditional publish/subscribe model.
或者,您可以找到提供某种传统发布/订阅模型的第三方库。
Or, you can build your own from scratch which really just involves keeping a list of callback functions that are associated with a specific event so when that event is triggered, you can call each callback function.
或者,您可以从头开始构建自己的,这实际上只涉及保留与特定事件关联的回调函数列表,以便在触发该事件时,您可以调用每个回调函数。
回答by SNag
If you came here looking for the jQuery
way of doing this, here you go:
如果你来这里是为了寻找jQuery
这样做的方法,那么你去吧:
Add the event broadcast/dispatch code:
添加事件广播/调度代码:
Syntax:$(<element-name>).trigger(<event-name>);
.
语法:$(<element-name>).trigger(<event-name>);
.
Example:
例子:
$.ajax({
...
complete: function () {
// signal to registered listeners that event has occured
$(document).trigger("build_complete");
...
}
});
Register a listener for the event:
为事件注册一个监听器:
Syntax:$(<element-name>).on(<event-name>, function() {...});
句法:$(<element-name>).on(<event-name>, function() {...});
Example:
例子:
$(document).on("build_complete", function () {
NextTask.Init();
});
Note:
Doing it this way: $(document).build_complete(function() {...});
leads to an error: Uncaught TypeError: $(...).build_complete is not a function
.
注意:这样做:$(document).build_complete(function() {...});
会导致错误:Uncaught TypeError: $(...).build_complete is not a function
。