My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

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 ;-)