X Project, Pt2: More on Events, Leaks, and IE
- October 5th, 2009
- Posted in Code . JavaScript
- Write comment
Picking up where I left off in ‘Hacking together’, which we’ll now call Pt.1, Let’s look at the entirety of the addEvents section of the library in browsers which aren’t named IE…
if (document.addEventListener) {
//w3 standard events model
X.addEventHandler = function(element,type,handler){
element.addEventListener(type,handler,false);
};
X.removeEventHandler = function(element,type,handler){
element.removeEventListener(type,handler,false);
};
X.stop = function(event) {
event.stopPropagation();
};
X.prevent = function(event) {
event.preventDefault();
};
} //end
Now to address the IE events model and the (hopefully) soon-to-be-a-thing-of-the-past memory leak issue. If we stroll back in time to 2005 there was a contest held over at Quirksmode for a JavaScript solution to the addEvent challenge. The winner was (to no great suprise) John Resig. That entire post saga is required reading imho. One of the judges of the contest, Dean Edwards wrote this solution, from which I am using a slightly modified version.
//IE or other non standards event model-------------
X.addEventHandler = function(element,type,handler) {
//check for guid, assign one if not present
if(!handler.$guid) handler.$guid = X.addEventHandler.guid++;
//create a hash for the element's event types
if(!element.events) element.events = {};
//create a hash of event handlers for each element/event pair
var handlers = element.events[type];
if(!handlers) {
handlers = element.events[type] = {};
//store the existing handler if exists
handler[0] = element["on" + type];
}
//store the event handler in the hash
handlers[handler.$guid] = handler;
element["on" + type] = X._handleEvent; //called when event fires
};
X.addEventHandler.guid = 1; //counter to generate the guids
X.removeEventHandler = function(element,type,handler) {
//delete a single handler from the hash table
if(element.events && element.events[type]) {
delete element.events[type][handler.$guid];
}
};
X.prevent = function(event) {
event.returnValue = false;
};
X.stop = function(event) {
event.cancelBubble = true;
};
X._handleEvent = function(event) {
//need a return val
var returnVal = true;
//IE uses a global event object
event = event || window.event;
//get a ref to the hash of event handlers
var handlers = this.events[event.type];
//execute each one
for(var i in handlers) {
this.$handleEvent = handlers[i];
if(this.$handleEvent(event) === false) {
returnVal = false;
}
}
return returnVal;
};
}
IE has a serious flaw if not corrected: When your attached function gets fired, the ‘this’ reference refers to the worthless ‘window’, when, in fact, it should refer to the parent object (I think I’m paraphrasing J.Resig there). This code addresses that by creating a hash table of event handlers with unique ids bound to your target element, assigning a ‘handleEvent’ method to be called when your event fires. This passes the object correctly and maintains scope (this). You should walk through this series of methods with IE’s developer tools JavaScript debugger, which is the best way to see how this works in real-time. Then there is a removeEventHandler to allow assigned handlers to be removed (more on that in a moment), as well as IE methods for preventing default behavior and stopping event propagation.
So, back to removeEvent and the IE memory leak possibility. This code does not use attachEvent() to handle events, which unless I am mistaken was the biggest problem with IE’s memory manager understanding which event handlers could be reclaimed by the garbage collector. See Douglas Crockford’s post here. Admittedly, this little portion of a discussion on the IE memory leak issue is a tiny drop in one seriously big-assed ocean. There is so much material out there on this subject alone you could get lost in it. I don’t really want to go down that path any further here. We’ll bind events without attachEvent, we’ll set a removeEvent handler on the events we bind and we’ll move on. A real solution would be don’t use IE, but I digress…
I have made a seperate page on the blog called ‘x.js’ for the code so far. Next I want to go into using object literals as a way to organize your code which will use the X library and some syntactic sugar to make for less verbose script, until then…


No comments yet.