Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Saturday, August 4, 2007

Module Pattern Template

So, as most of you know, I have been swamped with work lately. However, I promised myself that I would get you all a detailed article by the end of this week, regardless of how busy I am. In the near future I want to get back into comparing the different Frameworks, however, those articles take 5-10 hours to write and I just do not have that much time today. Instead, lets discuss the Module Pattern some more. In this article, I am going to show you my template for organizing my module patterns and discuss some details and gotchas about it.

First, why use the module pattern? The module pattern is best used with objects that are instantiated once (or very few times) per page. The module pattern does not leverage the power of prototype based OOP as the Functions are not being attached directly to the prototype of the Object. Instead you are instantiating a function and creating a closure thereby enclosing a self contain Object, which is more expensive in CPU cycles and memory when called frequently. I use the module pattern for 3 reasons, when writing: widgets, managers (like an Event Manager), and business logic for pages.

Here is an example of a module pattern that I use for managing the business logic of a page, which is the business need that I use the Module Pattern for most frequently:

Template.js

/** * Copyright (c) 2007, Matt Snider, LLC. All rights reserved. * Version: 1.0 */ /** * The PageName class manages the business logic of the PageName page * @namespace Core.Biz * @class PageName * @dependencies library */ Core.Biz.PageName = function() { // // Object namespace; private variables go here // var self = null; // internal object to reference public self // // Module dom namespace; id references to the DOM and other DOM objects go here // var dom = { }; // // Module evt namespace; event callbacks go here // var evt = { }; // // Module req namespace; AJAX request and callbacks go here // var req = { }; // // Public methods and constants // return { /** * The DOM selector class to identify example DOM elements * @property CLASS_EXAMPLE * @type String */ CLASS_EXAMPLE: ‘example’, /** * Some publicly available method */ publicDoSomething: function() { }, /** * initialize the object, put elements here that use global object elements (like static variables) */ init: function() { // initialize DOM references that are not null for (var k in dom) { if (isString(dom[k])) { dom[k] = $(dom[k]); } } self = Core.Biz.PageName; } }; }();

In this example ‘Core.Biz.PageName’ will create this object:

Core.Biz.PageName = { CLASS_EXAMPLE: String, publicDoSomething: Function, init: Function }

The object will be created when your page loads, but the internal objects that require the DOM should be put inside the ‘init’ Function and that function should be called when the document is ready (for best performance) or when window loads (if you do not use a powerful enough Event management Toolkit). Inside the closure Function, I generally create 3 namespaces (unless one is not needed), which helps me organize and manage my Object, these are: dom, evt, and req.

The ‘dom’ namespace will generally have the String IDs that I use to find elements on a page, or null, if I am going to initialize the DOM node reference through some other means in the ‘init’ Function. That namespace might look something like this:

var dom = { body: ‘projectBody’, someAnchor: ‘link1′, someOtherElem: null };

By putting this namespace first all other functions of the object can reference these elements. The ‘init’ function will automatically call document.getElementById (or equivalent depending on your Framework) on any String you defined in the namespace, so thereafter the Object members will reference DOM nodes. I would define ’someOtherElem’ in the ‘init’ Function as well, maybe by calling “dom.someOtherElem = dom.body.getElementsByTagName(’div’)[0];”.

The variable ’self’ is an internal shortcut to reference the public object. Initially ‘null’, you assign the ‘Core.Biz.PageName’ Object to it during the ‘init’ Function. Since references to ’self’ will not be evaluated until those Functions are called, it is safe to do use this Object as long as you run the ‘init’ Function first. Using ’self’ helps to prevent memory leaks or circular logic, and you do not have to worry about managing ‘this’. I also use it if I need to call an internal method that is not yet instantiated. For example you would not normally be able to access methods in the ‘req’ namespace from ‘evt’ because ‘req’ is declared after ‘evt’. However, as shown in the ‘evt’ namespace discussion below, you can circumnavigate this issue, by calling a public method on ’self’.

The ‘evt’ namespace will contain all non-trivial event callback functions for events attached to DOM nodes. These events should be attached in the ‘init’ Function after you have finished declaring your ‘dom’ namespace. If using YUI it might look something like this:

var evt = { onAnchorClicked: function(e) { var targ = YAHOO.Util.Event.element(e); CBP.publicDoSomething(); } }; … init: function() { … YAHOO.Util.Event.addListener(dom.someAnchor, ‘click’, evt.onAnchorClicked); … }

The ‘req’ namespace will contain all AJAX request and callback functions. I find this namespace helpful, because I can organize all my AJAX logic in the same place. If you do not use AJAX in your application or the Object does not manage AJAX, then omit this namespace.

The ‘init’ Function will be used to initialize elements of the Object that require the DOM. The first loop is included to do the automatic conversion of the ‘dom’ namespace ID references into DOM nodes. I then declare the ’self’ Object so that any internal references to the public Object are readily available. Thereafter, I will attach events, AJAX, and initialize other widgets used by the page. If you are using YUI I recommend the following line of code be included right after ‘Core.Biz.PageName’ is initialized to fire the ‘init’ Function as soon as the DOM is ready and before the window is completely loaded:

YAHOO.util.Event.onDOMReady(Core.Biz.PageName.init);

That about wraps things up. This is a complicated subject and if you have any questions, do not hesitate to ask. Also, I would be interested in hearing about how you organize your module pattern objects and any pointers you might have.

posted by Matt Snider at 4:26 pm  

Thursday, July 26, 2007

Detect when DOM Element is in viewport

I just read a good article by Dustin Diaz (formerly of YAHOO) about detecting where elements are in regards to scrolling and the viewport. It is simple and very powerful, so I thought I would share it with you. Also, I am overworked right now and have not had time to write any material of my own :(.

element-scroll-into-view

posted by Matt Snider at 3:49 pm  

Sunday, July 8, 2007

How to improve YUI hasClass method

On my project, Mint, I have reached a point, where the code is mostly stable and decided to start looking for ways to improve the performance. I checked out various JavaScript profiling techniques, deciding that the Firebug profiler was probably the most accurate. I then started profiling the different pages and realized (to my surprise) that a lot of time spent in the ‘YAHOO.util.Dom.hasClass’ method. I use ‘getElementsByClass’ method a lot, so this method is hit frequently. Therefore, since ‘hasClass’ was used the most, any performance improvement to that method would generally improve the performance of Mint.

Here is the YUI method found in dom.js:

         /**
         * Determines whether an HTMLElement has the given className.
         * @method hasClass
         * @param {String | HTMLElement | Array} el The element or collection to test
         * @param {String} className the class name to search for
         * @return {Boolean | Array} A boolean value or array of boolean values
         */
        hasClass: function(el, className) {
            var re = new RegExp('(?:^|\s+)' + className + '(?:\s+|$)');

            var f = function(el) {
                return re.test(el.className);
            };

            return Y.Dom.batch(el, f, Y.Dom, true);
        },

So what is taking a long time here? creating and executing the regular expression.

How do I improve this? replace the regex with something faster or find a way to create something that is already instantiated before this method is hit

I first choose to replace the regular expression (regex) with a call to ’split’ method, of String, on the DOMElements ‘className’. I noticed about a ‘0.5′ millisecond (ms) response time improvement to the execution time of the ‘hasClass’ method and almost a ‘0.1′ ms improvement to the whole function stack. The ‘0.05′ ms improvement is because converting the ‘className’ into an array using ’split’ is that faster than creating a new regex. Also, the execution of ‘batch’ and ‘f’ Functions are improved a combined ‘0.05′ ms, because executing the ‘indexOf’ method on a small array is faster than ‘test’ method of the regex. So, replacing the regex with an array does improve the execution time by a reasonable amount. It will be hard to notice the improved performance on any data set < 1000, however, it is always faster, so you are not hurting by using this change with smaller data sets.

Here is what I came up with:

 /**
		 *  Determines whether an DOMElement has the given className
		 *  @param  el {String/DOMElement/Array}        The element or collection to test
		 *  @param  className {String}                  The class name to search for
		 *  @return {Boolean/Array}                     A boolean value or array of boolean values
		 */
		hasClass: function(el, className) {
			var re = el.className.split(' ');
			var f = function(el) {
				return -1 != re.indexOf(className);
			};
			return Y.Dom.batch(el, f, Y.Dom, true);
		},

I compiled all my tests into Table 1A. The table shows the ms of ‘owned time’ (time the execution thread was actually in that method) that each function had. I setup a simple page with 3 div elements, one without a class, one with a single class, and one with several classes. I then grabbed one element at a time and executed ‘hasClass’ on it 1000 times. I did this 5 times, then took the average of those runs and recorded it as a trial. So each trial consists of 5000 calls to ‘hasClass’. I then modified the ‘hasClass’ method and repeated. ‘hasClass’ calls ‘batch’, which calls the ‘f’ Function, so I have included their ‘owned time’ as well. I did not throw out outliers as I was only proving that the Array method is faster than the Regex method and not trying to accurately estimate how much faster.

Table 1A:
http://spreadsheets0.google.com/ccc?key=pJL0oH5TVaRjjog0qePS2bQ&hl=en_US

Something this data shows that warrants further investigation is: why does ‘indexOf’ method execute marginally faster on an array with a single element versus an Array with no elements? If you look at the average runtime of the ‘f’ Function using the new method, the runtime of ‘f’ is slightly higher when there is no class than when there is one. I produced two more sets of data for each case and got comparable results.

I would have liked to try an approach that moves the instantiation completely out of the method, but I couldn’t think of a good technique. If you have any ideas how to further improve this, let me know.

posted by Matt Snider at 3:56 pm  
« Previous Page

Powered by WordPress