React Flux dispatcher vs Node.js EventEmitter - scalable?

When you use Node EventEmitter, you subscribe to one event. Your callback is only executed when this particular event is fired:

eventBus.on('some-event', function(data){ // data is specific to 'some-event' }); 

In Flux, you register your store with a dispatcher, then your store is called when each individual event is dispatched. The storeโ€™s task is to filter through each event that it receives and determine whether the event is important for the store:

 eventBus.register(function(data){ switch(data.type){ case 'some-event': // now data is specific to 'some-event' break; } }); 

In this video, the facilitator says:

"Stores subscribe to actions. In fact, all stores receive all actions, and this makes it scalable."

Question

Why and how is sending each action to each store [presumably] more scalable than just sending actions to specific stores?

+5
source share
2 answers

The scalability in question here is more about scaling the code base than scaling in terms of software performance. Data in streaming systems is easily monitored, because each store is registered for each action, and actions determine each application event that can occur in the system. Each store can determine how it should be updated in response to each action, without the need for a programmer to determine which stores are connected to which actions, and in most cases you can change or read the code for the store without worrying about how it affects to any other store.

At some point, the programmer will need to register the store. The store is very specific to the data that it will receive from the event. How to accurately search for data inside the store is better than registering for a particular event, and does the store always expect the data that it needs / cares for?

Actions in the system are things that can happen in the system, as well as relevant data for this event. For instance:

  • The user is logged in; comes with user profile
  • User added a comment; comes with comment data, identifier of the item that was added to
  • The user updated the message; comes with message data

So you can think of actions as a database that stores can know about. Every time an action is sent, it is sent to each store. Thus, at any point in time you only need to think about your data mutations in one storage + action at a time.

For example, when a message is updated, you may have a PostStore that monitors the POST_UPDATED action, and when it sees it, it will update its internal state to save the new message. This is completely separate from any other store that can also take care of the POST_UPDATED event - any other programmer from any other team working on the application can make this decision separately, with the knowledge that they can connect to any action in the action database, which may take place.

Another reason it is useful and scalable in terms of the code base is the inverse of control; each store decides what actions it cares and how to respond to each action; all data logic is centralized in this repository. This contrasts with a pattern such as MVC, where the controller is explicitly configured to call mutation methods on models, and one or more other controllers can also call mutation methods on the same models at the same time (or at different times); The logic for updating data is spread across the system, and understanding the data flow requires understanding every place that a model can update.

Finally, another thing to keep in mind is that registration or not registration is a kind of semantics question; trivially ignore the fact that the store receives all the actions. For example, in Fluxxor in stores, there is a method called bindActions that associates specific actions with specific callbacks:

 this.bindActions( "FIRST_ACTION_TYPE", this.handleFirstActionType, "OTHER_ACTION_TYPE", this.handleOtherActionType ); 

Despite the fact that the store receives all the actions, under the hood it searches for the type of action in the internal map and calls the corresponding callback in the store.

+5
source

I asked myself the same question and do not see technically how registration adds a lot, in addition to simplification. I will present my understanding of the system in such a way that I hope that if I am mistaken, I can be corrected.

TL; DR; EventEmitter and Dispatcher perform similar tasks (pub / sub), but focus their efforts on different functions. In particular, the waitFor function (which allows one event handler to ensure that another has already been called) is not available in the EventEmitter. The dispatcher focused on the waitFor function.


The end result of the system is communication with stores that an action has occurred. Will the store "subscribe to all events, then filter" or "subscribe to a specific event" (filtering on the dispatcher). Does not affect the final result. Data is transferred in your application. (the handler always only includes the type of event and processes, for example, it does not want to work with all events)

As you said: "At some point, the programmer will need to register the store." This is just a matter of subscription fidelity. I do not think that a change in fidelity has any effect on the "inversion of control", for example.

The added function (killer) in facebook Dispatcher is the ability to โ€œwaitโ€ for another store to handle the event first. The question is, does this feature require each store to have only one event handler?

Let's look at the process. When you submit an action to the Dispatcher, it (omitting some details):

  • Iterates through all registered subscribers (to the dispatcher)
  • calls a registered callback (one per store)
  • callback can call 'waitfor ()' and pass 'dispatchId'. This internally refers to a callback registered in another store. This runs synchronously, causing the other store to receive the action and update first. This requires that "waitFor ()" be called before your code that processes the action.
  • The callback called by waitFor includes the type of action to execute the correct code.
  • callback can now run its code, knowing that its dependencies (other stores) have already been updated.
  • callback switches the type action to execute the correct code.

This is a very easy way to resolve events.

Basically, all calls are called, but in a specific order. And then switch to executing only certain code. Thus, it looks like we just triggered the add-item event handler in each store in the correct order.

If the subscription is where at the callback level (not the "storage level"), is this still possible? That would mean:

  • Each store registers several callbacks for certain events, keeping a link to its "dispatchTokens" (the same as at present)
  • Each callback will have its own "dispatchToken"
  • The user will still โ€œwaitโ€ for a specific callback, but will be a specific handler for a specific repository.
  • The dispatcher then only needs to send callbacks of a certain action in the same order

Perhaps smart people on facebook have figured out that it will actually be less effective to add complexity to individual callbacks, or perhaps this is not a priority.

+2
source

All Articles