Hello! I want to show my piece of CoffeeScript for declarative subscription and event handling.
Prehistory
I have 5 years of engineering experience that includes .NET (+ forms, + WPF, + .NET MVC), Java (+ Swing, + Tapestry5, + Groovy), JavaScript (+ CoffeeScript, + Node).
Last year I actively write my own one-page web application that works without rebooting, (which will be discussed in future releases). The entire dynamic part of the user interface is created on the client, only data comes from the server. As often happens in UI, I am dealing with a component tree. Of course, for organizing the interaction of the tree, I need a mechanism for sending and processing events. I decided to write my own, and not to use Backbone, or something from Google Closure. In any case, I had the experience of implementing the Etude Listener (Listener pattern).
')
Class IspuscatorEvents of the first version If you wanted to listen to him - just wrote you down into an array of listeners. When the event “Ch” occurred, he went around the array, and searched for listeners with the “NAC” method, and called it. Like in Swing / .NET.
Everything worked fine for a small number of Heaters. With the growth of the system came the problem of overlapping event names between different Spots. The subscriber carried out the same method “nch”, even if the “H” came from different Emitters. Then it was more familiar to JS, EventEmitter, as in jQuery / NodeJS. I will not particularly delay ...
SuperEmitter
Now I am working with a tabular view of the tree “emitter -> events -> reactions”. Example:
class Brain extends SuperEmitter event_table: [ # [ 'ear' , [ [ 'snake_heard' , [ 'emit_adrenaline' 'look_around' ] ] ] ] [ 'eye' , [ [ 'food_spotted' , [ 'emit_noradrenaline' 'hunt' 'emit_endorphins' ] ] [ 'predator_spotted', [ 'emit_cortisol' 'emit_adrenaline' 'run' ] ] ] ] [ 'nose', [ [ 'food_smelled' , [ 'look_around' ] ] [ 'blood_smelled' , [ 'emit_adrenaline' 'look_around' ] ] ] ] ] # constructor and instance members constructor = -> @ear = new Ear() @eye = new Eye() @nose = new Nose() # methods: emit_adrenaline: -> emit_cortisol: -> emit_endorphins: -> hunt: -> look_around: -> new Brain().bind_events()
Instead:
class Brain bind_events: -> @ear.on 'snake_heard', (args...) => # @emit_adrenaline(args...) # @look_around(args...) @eye.on 'food_spotted', (args...) => @emit_noradrenaline(args...) @hunt(args...) @emit_endorphins(args...) @eye.on 'predator_spotted', (args...) => @emit_cortisol(args...) @emit_adrenaline(args...) @run(args...) @nose.on 'food_smelled', (args...) => @look_around(args...) @nose.on 'blood_smelled', (args...) => @emit_adrenaline(args...) @look_around(args...) # ..
This is my
ognivo / super-emitter library . It allows you to remove the entire connective code, and focus on sources, events and reactions. Code less, it is cleaner, more granular. The format allows you to see where the sequence of answers comes from.
Moreover, a table is data, and with it you can do everything you can do with data. Compare, glue, clone, and so on.
Demo
Demo online . This is from the demo folder in the repo. You can clone the repo, you can run
npm install super-emitter
. I want to make a larger demo, but so far with time.
Release and receive events
SuperEmitter is implemented as a class. It has an emit method through which the event is fired and its arguments are passed. Arguments must be packed into an array when called, which highlights them visually. The function subscribed to the event takes arguments through the usual list of parameters.
brain = new Brain() brain.bind_events() brain.emit('adrenaline') brain.emit('adrenaline', [dosage_ml = 300, noradrenaline = true]) brain.on 'adrenaline', (dosage_ml, noradrenaline) -> console.log "I'm running from something"
Requirements
The instance to which you subscribe must have an “on” method with a signature (is there a Russian word?) Event_name, callback. Suitable jQuery wrappers, KineticJS shapes (shapes), instances of the class SuperEmitter.
The standard method for DOM components addEventListener has the same signature, so nothing complicated with it either. Once I had to subscribe to popstate from the window, respectively, everything was decided window.on = window.addEventListener.
What not
There is no ascent and interception of events. I don’t see any reasons yet, I like that for each level of the component hierarchy I see all the events that go through it.
I will be glad to criticism, praise and additions.
ZY: I intentionally chose the word emitter, and not the source.