Leak free event class that doesn’t use the unload event

June 9th, 2008 by Spocke

I recently read an interesting blog post at Ajaxian it described that Hedger Wang discovered that some Chinese fellow was able to fix the circular reference memory leak in IE using a finally statement. This got me very exited since it would remove the need to use the unload event to cleanup memory leaks. There are lots of issues using the unload event to cleanup memory leaks I blogged about one of them earlier and using an non unload approach would make things a lot easier and more efficient.

Here is the proof of concept class and you can see it in action at the example page.

(function() {
	window.EventUtils = {
		eventFuncs : [],

		addEvent : function(o, n, f) {
			var el, id;

			// Resolve element by id if needed
			o = typeof(o) == 'string' ? document.getElementById(o) : o;

			if (o.attachEvent) {
				// Since we can't use attachEvent we need to generate an unique id for the object
				// and place functions in an array one for each object
				el = EventUtils.eventFuncs;
				id = o._evtID;

				if (!el[id]) {
					// Generate new unique id
					id = o._evtID = el.length;

					// Add event listener old fashion way instead of attachEvent
					o['on' + n] = function() {
						var i, l, e = window.event, li;

						e.target = e.srcElement; // Force W3C style

						// Execute each event listener in order
						for (i = 0, li = el[e.target._evtID], l = li.length; i < l; i++)
							li[i](e);
					};

					// Create array with first function
					el[id] = [f];
				} else
					el[id].push(f); // Push in more functions

				// Fix the IE leak
				o = null;
			} else if (o.addEventListener)
				o.addEventListener(n, f, false);
			else
				o['on' + n] = f;

			return f;
		},

		removeEvent : function(o, n, f) {
			var i, li;

			// Resolve element by id if needed
			o = typeof(o) == 'string' ? document.getElementById(o) : o;

			if (o.detachEvent) {
				li = EventUtils.eventFuncs[o._evtID];

				if (li) {
					// Detach event listener by looking for it and remove it from the array
					for (i = 0; i < li.length; i++) {
						if (li[i] === f)
							li.splice(i, 1);
					}
				}
			} else if (o.removeEventListener)
				o.removeEventListener(n, f, false);
			else
				o['on' + n] = null;
		}
	};
})();

Here is a simple example on how to use the class it adds two events and removes one of them this sample code can be seen live running the example page:

var f;

EventUtils.addEvent('elm', 'click', function(e) {
	alert('Listener 1: ' + e.target.id);
});

f = EventUtils.addEvent('elm', 'click', function(e) {
	alert('Listener 2: ' + e.target.id);
});

EventUtils.addEvent('elm', 'click', function(e) {
	alert('Listener 3: ' + e.target.id);
});

EventUtils.removeEvent('elm', 'click', f);

Posted in Blogs, Cool stuff, Development

Comments are closed.