Javascript中客户端消息框架设计原理详解

Javascript中客户端消息框架设计原理详解
哇,这是个危险的话题,不是吗我们基本的理解肯定会与我们对问题的理解的变化得到解决。所以我不会说谎-我明白一年前自然是不幸的,因为我确信我会写快跟我6个月了。所以,这篇文章是我在看一眼对于Javascript客户端消息模式成功的一些关键点的应用。

1)了解调解人和观察者之间的区别

大多数人喜欢使用发布/订阅(酒吧/子)在描述任何事件/消息机制,但我不认为这个词可以很好的与抽象。当然,在根,有些东西已经订了,其他的事情发表的事件。但出版商和用户在什么级封装在一起可以做一个很好的模型变得昏暗起来。所以,区别在哪里
观察者

观察者模式包含一个对象是由一个或多个观察者观察的对象。通常,记录所有的痕迹观察,通常使用表来存储用户的回调观察员。这些订户是为了收到通知而订阅的。通知:(哦,双关语,我有多喜欢它们(观察观察,注意)

var观察者= {
听:函数(){
console.log(Yay更老生常谈的例子…);
}
};
var elem = document.getelementbyid(陈词滥调);
elem.addeventlistener(单击
一些需要注意的事情是:

我们必须直接引用这个对象。
该对象必须保持某种内部状态,并保持观察者的回调跟踪。
有时候听众不使用任何参数,返回该对象,从理论上讲,有可能是0-N *参数,这取决于如何有趣,他们将成为以后。
n实际上不是无限的,但为了讨论的目的,它指的是我们永远无法达到的极限。
第三者

中介模式引入了对象和观察者之间的第三方,有效解耦两,并将它们之间的通信。调解员的API可以为出版那样简单,订阅或取消订阅,或在某一领域的实现可以被用于隐藏这些方法在一些更有意义的语义。服务器端的实现我喜欢域范围而不是简单的,但有一个通用的中介没有规则的限制,这是不寻常的,有一个想法,一个总代理是一个信息经纪人。在任何情况下,结果是相同的-具体的对象和观察者不再直接知道对方:

天真的乐趣!
var中介{ {
_subs:{ },
一个真正的订阅至少要检查一下以确保
回调实例未注册2
他们在哪里 / /他妈的,找到这个人!
订阅:函数(主题,回调){
这_subs { } =这个话题。。_subs { } { } | |话题;
这个话题。_subs { }推(回调);
},
lolwut没有能力通过功能 / /背景:-)
发布:函数(主题,数据){
VaR的潜艇=这话题。_subs { } | | { };
subs.foreach(功能(CB){)
CB(数据);
});
}
}
无功fathertime =功能(MED){ this.mediator =医学;};
fathertime.prototype.wakeywakey =函数(){
This.mediator.publish(报警。时钟
时间:上午6
CanSnooze:当然没有起床懒屁股
});
}
函数(中介){
this.mediator =中介;
this.mediator.subscribe(时钟报警。
};
developer.prototype.pleasedno =功能(数据){
警报(老天,这是+ +data.time。请让它停下来。;
}
无功fathertime =新fathertime(中介);
新开发人员(中介);
FatherTime.wakeyWakey();
您可能认为,除了实现一个特别纯净的中介,一个特定的对象也不再负责保存订阅列表。fathertime和开发商开发商永远不会互相了解。他们只是共享一个消息在未来看到我们这是一个非常重要的合同。很好,吉姆。这仍然是一个发布者/用户对我来说,什么是点我是否选择某个方向来真正发挥作用哦,继续吧,亲爱的读者们,继续吧。

2)知道何时使用中间人和观察员。

利用当地观察员和中介机构,即用的组件,和调解员像远程components.anyway.the原理之间的沟通,我把这种情况是TL;DR(太长;不读)(太长,不懂),但在任何情况下,最好是在串联连接

简单地说,这确实是一个麻烦的问题,就好像你用140个字把几个月的细节挤到一个沟里一样。实际上回答这个问题的问题肯定不是简明扼要的:

除了数据映射之外,观察者是否需要引用其他项目例如,View视图有多种原因直接引用它的模型,这是一种非常自然的关系,不仅在模型改变时呈现模型,而且调用模型的事件处理

如果观察者和观察者是只依赖于数据之间的关系,我想用中介酒吧/ sub.the两骨干通信。视图或模型的观察者是合适的。例如,控制导航菜单的视图是一个用户侧所需要的信息(反应以目前的水平)。吊坠不需要参考导航视图。它只需要导航视图来提供信息。更重要的是,导航视图可能不是唯一的信息源,并且其他视图也可以使用。

它看起来很好,很全面,但实际上有一个露点:如果我为对象定义一个本地事件,我希望观察者直接调用,它可以由订阅者间接访问。这就是为什么我必须把它放在一起:您将本地事件推送或桥接到消息组。您需要更多的代码吗这是很可能的,但总比你把观察结果传给所有的观察者好…
3)选择性地将本地事件提交给总线

首先,我几乎只使用观察者模式的触发事件在Javascript中。这是我们一次又一次的适应模式,但客户更流行的方式辅助库行为基本上是中介机构的混合物,它为我们提供了API作为一个观察者模式。当我第一次写postal.js,我开始走进以中一切的阶段。在原型和建设者我写,调用发布和订阅都是司空见惯的。当我受益于这种变化的自然解耦,非基本的代码开始似乎充满了基地的一部分。构造函数的参数是一个渠道无处不在,和订阅创建新实例的部分。原型直接发布数值的巴士(甚至当地的用户不能直接和必须听公共汽车信息)。带来总线分为几部分APP开始像代码的品味这些显而易见的事情。代码的描述似乎总是被打断,例如,发布给所有用户,等等!等uff01listen,passage.ok,走吧,突然,我的测试开始依赖公共汽车做低级别的单元测试,感觉有点不对。

钟摆向中间摆动。我意识到我应该保持本地API和扩展可以达到通过中介时所需的数据。例如,我的脊梁视图和模型仍然使用普通backbome。事件行为将事件发送到当地的观察员(即模型的事件是由相应的视图时观察到的)。要知道在模型变化的应用程序需要的其他部分,我开始桥的事件,通过这些线路的公共汽车:

无功somemodel = backbone.model.extend({
初始化:函数(){
This.on(变化:superimportantfield
postal.publish({
道:somechannel
主题:OMG。超级重要。字段。更改
数据:{
MuyImportante:价值,
otherfoo:otherbar
}
});
});
}
});
它是实现当可能推动事件的消息总线的重要,局部事件和消息必须被认为是独立的合同,至少在概念。换句话说,你必须能够修改内部或局部的事件不会破坏信息的合同。这是要记住的重要事实,否则你提供一种新的方式和紧耦合在一路回去!

当然,上面的模型可以在没有消息总线的情况下进行测试。如果移除本地事件和总线之间的逻辑,我的视图和模型仍然工作得很好。不过,这是七行(虽然格式化)的一个例子。只需要桥接四个事件就需要三十行代码。

哦,你怎么考虑这两个因素呢本地通知适合于直接观察者,而相关的事件可以扩展,这样您的对象不需要向所有对象发送一个圆——不需要代码扩展。

4)将模板隐藏在您的框架中

这是不是说,在上面的例子中的代码——事件的访问总线--语法或观念是错误的(假设你接受本地和远程/桥接事件的概念)。然而,这是培养良好的习惯对代码基础作用的一个很好的例子。有时我们听到很多人抱怨像代码(尤其是当LOC是代码的质量的唯一判断)。在这种情况下,我同意。这是一个可怕的模型。以下是我用的桥的骨干对象的局部事件postal.js模式:

连接出版物/订阅的逻辑
在我们的习惯msgbackboneview构造函数 / /存在
无功集中= msgbackboneview.extend({

类名:i-am-classy

桥接由此视图触发的本地事件
出版物:{
这是更common'shorthand ' / /语法
关键名称是事件的名称。这个
通道主题值在邮政中。所以这
的bridgetoofar事件会 / /手段
邮政 / /发布通讯通道
一个话题 / / thats.far.enough使用默认的。
传递给事件回调的第一个参数
成为消息有效载荷。
bridgetoofar:通信那。远不够

普通的方法 / /然而,像这样的作品:
键仍然是将被桥接的事件/名称。
该值是一个提供通道名称的对象,
一个主题(可以是一个字符串或函数返回
返回的可选数据函数
对象应该是消息/有效负载。
bridgeburned:{
频道:通讯
主题:匹配。
数据:函数(){
返回{编号:this.get(ID),foo:'bar};
}
},

这就是我们订阅总线并调用的方式。
处理传入消息本地的方法
订阅:{
关键是要调用的方法的名称。
该值是订阅的通道主题。
所以这将订阅 / hotchannel通道
一个主题绑定,包含开始、燃烧、*和任何
消息到达被路由到 / / burnitwithfire
在视图上。方法
BurnItWithFire:hotchannel开始燃烧。*
},

BurnItWithFire:功能(数据包络){
使用消息数据和 /或信封进行填充
}

其他/连线等。
});
显然,你可以在几个方面这些东西--选择总线式的框架,这是比模板方式无关的要少,是众所周知的骨干人员。桥更容易当你控制事件发送器同时消息总线的实现。这里是桥接monologue.js发射机postal.js例。

独白 / / /邮政the'monopost'add-on:使用
假设我们有一个具有实例的工作实例
在它的原型、方法链等方面,键是事件。
绑定以将本地事件主题匹配到,如果匹配
它发布到指定的通道中。
值(同一主题/使用值)
邮政工人({
比赛的东西似的。# thischannelyo
秘密。酱。*:seeecretchannel
另一个。*。话题:yaymoarchannelschannel
});
以不同的方式使用模板是一个令人愉快的好习惯,现在我可以独立测试我的本地对象,桥接代码,甚至测试21的生产和消费期望的消息过程。

同样重要的是要注意,如果我需要在上面的场景中访问通用的邮政API,没有什么能阻止我这样做。
5)信息是一个契约——实施它的明智选择。

有两种方法可以将数据传递给订阅者,也许可以在他们身上贴上更多的官方标签,我会这样描述他们。

0-N参数
盖(或单个物体负荷)
看看这些例子:

0-N / /参数
This.trigger(someguyblogged
信封 /样式
This.emit(someguyblogged
名字:吉姆
姓:他们
catery:Javascript
});
*
在发射器的发射monologue.js,称以上
实际上会出版一个看起来相似的信封。
这:
{
主题:someguyblogged
时间戳:2013-02-05t04:54:59.209z
数据:{
名字:吉姆
姓:他们
catery:Javascript
}
}
* /
一段时间后,我发现少了很多的麻烦(和代码)比0-n个参数,0-n个参数的方法,主要是由于两个原因的挑战(我的经验):首先,通常情况下,当事件被触发时,你还记得哪些参数呢不记得了吗嗯,我想我来看看扳机的来源,这不是一个很好的方法,对吧但是,它可以中断代码的正常流程,可以使用调试工具执行条件检测参数值,并根据这些值推断标签,但是哪一个更简单呢-看到一个1.21参数值,迷惑它的意义,或者检测一个对象,发现千兆位:1.21 }。第二个原因是由于可选数据与事件的转移,以及方法签名的痛苦变得更长。
实话告诉你,吉姆,你在搭便车的小屋里。是的,也许,但是很长一段时间,我看到代码的基础正在膨胀和变形。它包含原始事件的简单的一个或两个参数,其中包括可选参数,这些参数稍后会变成错误的。

这是的开始。
This.trigger(someevent
有一天,它包含一切
This.trigger(someevent
但是,等待-第四和第五参数是可选的,因此也可以通过:
This.trigger(someevent
您可以检查第五个参数:真/假
!现在是较早的参数…
This.trigger(someevent
如果数据是可选的,就不会有测试,但需要更少的代码,需要更多的扩展性。通常情况下,它可以自我解释(感谢这些成员的名字),它可以通过一个测试一个对象一方面给调用者的回调方法之一。我还是要用0-n个参数使用它,但如果我决定,我会一直使用信封的方法--我的事件发送方和消息总线都是这样。(解释一下我的偏见,独白和邮政分享同一套,相同的数据结构去通道,独白不使用)

因此,用户的数据传输结构是合同的一部分,以信封的方式,您可以使用额外的元数据来描述事件(不添加额外的参数)。这种方法签名是契约的一部分,它与每个事件和订阅者保持一致。您也可以轻松编译一个信息结构的版本(必要时向其他覆盖层添加信息)。
6)消息拓扑比你想象的更重要。

没有银弹,但你要想想如何命名的主题和渠道如何设计消息负载的结构。我倾向于其中的一种方法:用一个数据通道模型映射、模型的名称前缀的主题,其次是其独特的身份,和然后通过操作({类型。id.operation }),或模拟他们的频道,主题是{ id.operation }。一个不变的习惯是自动响应的行为模式时,请求的数据。但并不是所有的操作对总线的要求。可能有一个简单的事件被发布到App呢。你的名字的主题描述事件(理想情况下)或者您是否陷入这样的陷阱,通过命名主题来描述订阅者的潜在倾向例如,包含route.changed或show.customer.ui主题信息,显示事件,其他的显示命令。仔细想想当你做出这些决定。命令是不坏,但在你需要一个请求/响应或命令,你会被那可以描述事件的数量感到惊讶。

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部