Sunday, May 02, 2010

Event driven application and the most basic Listener module

Event driven programming is a common technique particularly common in JavaScript applications.

When


The most classic application is the one with DOM and assigned listeners.
We have basically no idea about "what happens when" and we delegate asynchronous logic to our listeners, waiting for user actions.
This kind of approach could be implemented in whatever application creating a chain of events or notifications that must occur when something expected happens.
Other examples of event driven programming are sockets, Ajax calls, and any sort of notification that may occur in order to let the surrounding logic act accordingly.
Often combined with registry pattern, event driven programming can be found inside UI frameworks where components, as example, are notified when sub-components are added or removed. In this way the component always knows its status and it can change accordingly (redraw, repaint, properties, accessors, counters, other notifications).

What

Following the DOM example or, back in 2004, the ActionScript model, events are nothing more than callbacks associated via unique identifier: the event name. The natural order for these callback is FIFO and usually each callback is "fired" with the same object/event as single argument. One de-facto standard about events is that usually there is no need to add twice the same so that one event will be fired just once.
Since the order matter, there is no way to prevent events already assigned to do not fire. The same is for DOM events, preventDefault or stopPropagation won't stop other events associated with the same node to do not fire but, if used, the chain or the behavior after these events are fired may be different.

How

This is one of the most basic Listener implementation: it's a module, suitable for mixins, is a Singleton, usable and shareable across the whole application, and finally it's a little piece of code, basically unbreakable and reliable for what it does.
This is a basic usage example for the Listener module:

function MyListener() {
// create the "protected" listener hash
this.initListener();
}
MyListener.prototype = Listener;

var ml = new MyListener();

var test = function (arg) {
alert(ml === this && arg === 2); // true
};

ml.addListener("test", test);
// won't add the same event
ml.addListener("test", test);

// fire the event
ml.fireListener("test", 2);

// remove the listener
ml.removeListener("test", test);

// check precedent operation
alert(ml.hasListener("test", test)); // false

// fire a listener in any case
ml.fireListener("test", 2); // nothing happens


Why

With this basic functionality we can already start to create an event driven application firing events whenever it is necessary.
As example, an object with a remove/destroy method may involve soe notification. All we need to do in this case is to use something such:

this.fireEvent("destroy", this);

before or after destroy operations. In this way whatever other part of the application that added a listener may act accordingly and the chain of notifications can establish a new environment, if necessary.
The behavior is the same we can found in native DOM events listeners. If a listener is removed runtime it won't be fired and same is if a listener will be added runtime, it will be executed only next time unless we are not firing it again (which means all others will be fired again).

This post would like to be just a starting point for this kind of approach, sometimes we may need to deal with objects that don't know what could happen if one of them has been removed, added, created, or changed so in this way we have a basic component to deal with. Have fun ;-)

6 comments:

Andreas said...

this together with your 'Listener' implementation really helped me a lot with my approach of a small shortcut delegation tool.
while the licensing of your Listener is a bit unclear to me (mit style / that particular cc) i'm uncertain whether i may push my part unproblematically as a gist to github. provided that you'd permit, i would push it and furthermore drop you a line about where to find an example usage.
nevertheless thanks / greetings from pankow/berlin ;)

Andrea Giammarchi said...

glad you liked it, the license is Mit Style so no worries at all :-)

greetings from friedrichshain / berlin ;-)

Andrea Giammarchi said...

P.S. I have updated and optimized even more the script, adding comments as well.

Andreas said...

Well thanks a lot!!!
I just uploaded the first draft as a gist (to be found here: http://gist.github.com/396238 ).
If you're interested you can find the working draft for a live test at jsbin: http://jsbin.com/axisa3
It's currently anything but final, so there might (well rather *will be*) some glitches, but i didn't had the time to refine it yet.
cheers - i definitely owe you a beer or two ;)

Anonymous said...

this[_hash]||(this[_hash]={});
vs.
if(!this[_hash])this[_hash]={};

why the first construct ? (1 byte shorter ?) or just style ?

Andrea Giammarchi said...

that "if" does not pass JSLint, and once you don't care about it, one byte shorter could mean Kb in large application if you don't follow the style ... and performance speaking is the same ... so the question is why would you ever go for other styles ... is "if" better than an "OR"? Then we have a problem with JavaScript language!