React Flux调度器vs Node.js EventEmitter – 可扩展?
当你使用Node的EventEmitter时,你订阅一个事件。 您的callback仅在特定事件启动时执行:
eventBus.on('some-event', function(data){ // data is specific to 'some-event' });
在Flux中,您向调度员注册您的商店,然后当每个事件被调度时,您的商店被调用。 商店的任务是过滤每一个事件,并确定事件对商店是否重要:
eventBus.register(function(data){ switch(data.type){ case 'some-event': // now data is specific to 'some-event' break; } });
主持人在录像中说:
实际上,所有商店都会收到所有的动作,这就是保持可扩展性的原因。“
题
为什么以及如何向每个商店发送每个动作(大概)比只向特定商店发送动作更具可扩展性?
这里提到的可伸缩性更多的是扩展代码库,而不是缩放软件的速度。 stream量系统中的数据很容易追踪,因为每个商店都被注册到每个操作中,并且这些操作定义了系统中可能发生的每个应用程序范围内的事件。 每个商店都可以确定如何更新自己以响应每个操作,而不需要程序员决定哪些存储库连接哪些操作,并且在大多数情况下,您可以更改或读取商店的代码,而无需担心关于它如何影响任何其他商店。
程序员有时需要注册商店。 商店对于从事件中获得的数据非常具体。 在注册特定事件的过程中,如何更好地查找商店内的数据,并让商店始终期望它所需要/关心的数据?
系统中的操作代表系统中可能发生的事件,以及该事件的相关数据。 例如:
- 用户login; 附带用户configuration文件
- 用户添加了评论; 附带评论数据,它被添加到的项目ID
- 用户更新了post; 附带发布数据
所以,你可以把行动看作商店可以知道的事情的数据库。 任何时候发送一个动作,它都被发送到每个商店。 所以,在任何时候,你只需要一次考虑你的数据突变一个商店+行动。
例如,当一个post被更新时,你可能有一个PostStore
来POST_UPDATED
动作,当它看到它时,它将更新它的内部状态来存储新的post。 这与任何其他可能关心POST_UPDATED
事件的商店都是完全分开的,任何其他从事该应用程序的团队的程序员都可以单独作出决定,知道他们能够挂钩到数据库中的任何操作可能发生的行为。
另一个原因是在代码库方面是有用的和可扩展的,这是控制的反转; 每家商店决定它关心的行为以及如何回应每个行动; 所有的数据逻辑都集中在那个商店里。 这与MVC模式相反,在这种模式中,控制器被明确设置为在模型上调用变异方法,并且一个或多个其他控制器也可以在同一时间(或不同时间)调用相同模型上的变异方法。 数据更新逻辑通过系统传播,理解数据stream需要理解模型可能更新的每个地方。
最后,还有一点需要注意的是,注册与不注册是一个语义问题。 抽象出商店接受所有行为的事实是微不足道的。 例如,在Fluxxor中,商店有一个名为bindActions
的方法, bindActions
特定的操作绑定到特定的callbackbindActions
:
this.bindActions( "FIRST_ACTION_TYPE", this.handleFirstActionType, "OTHER_ACTION_TYPE", this.handleOtherActionType );
即使商店接收到所有操作,在内部映射下查找内部映射中的操作types,并在商店中调用适当的callback。
我一直在问自己同样的问题,不能从技术上看到注册如何增加了很多,超出了简化。 我会提出我对系统的理解,希望如果我错了,我可以纠正。
TLDR; EventEmitter和Dispatcher具有类似的用途(pub / sub),但将精力集中在不同的function上。 具体来说,“waitFor”function(允许一个事件处理程序确保已经调用另一个事件处理程序)不能用于EventEmitter。 调度员专注于“waitFor”function。
该系统的最终结果是与商店沟通已经发生了一个行动。 商店是否“订阅所有事件,然后过滤”或“订阅特定事件”(在调度员处进行过滤)。 不应该影响最终的结果。 数据在您的应用程序中传输。 (处理程序总是只启动事件types和进程,例如它不希望在所有事件上运行)
正如你所说的“程序员有时需要注册商店”。 这只是订阅忠诚的问题。 例如,我认为保真度的改变不会对“控制倒置”产生任何影响。
Facebook的Dispatcher中增加的(杀手)function是能够“等待”另一家商店,首先处理事件。 问题是,这个function是否要求每个商店只有一个事件处理程序?
我们来看看这个过程。 当你在Dispatcher上发送一个动作的时候(省略一些细节):
- 迭代所有注册的订户(到调度员)
- 调用注册callback(每个商店一个)
- 该callback可以调用“waitfor()”,并传递一个“dispatchId”。 这在内部引用由不同商店注册的callback。 这是同步执行的,导致其他商店接收行动,并首先更新。 这要求在处理动作的代码之前调用“waitFor()”。
- 由'waitFor'调用的callback切换动作types来执行正确的代码。
- callback现在可以运行其代码,知道其依赖关系(其他商店)已经被更新。
- callback开关的动作“types”执行正确的代码。
这似乎是一个非常简单的方法来允许事件依赖。
基本上所有的callback最终都是以特定的顺序调用的。 然后切换到只执行特定的代码。 所以,就好像我们只是按照正确的顺序在每个商店触发了“add-item”事件的处理程序。
如果在callback级别(而不是“商店”级别)的订阅,这仍然是可能的? 这将意味着:
- 每个商店将注册多个callback特定的事件,保持参考他们的“dispatchTokens”(与目前相同)
- 每个callback将有自己的“dispatchToken”
- 用户仍然会“等待”特定的callback,但是成为特定商店的特定处理程序
- 调度员然后将只需要以相同的顺序发送特定动作的callback
Facebook上的聪明人可能已经发现,这实际上不会增加个人callback的复杂性,或者可能不是优先考虑的事情。