Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

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  

Tuesday, May 29, 2007

Maintainable JavaScript

Nicholas Zakas, now of My YAHOO!, talks about maintaining your JavaScript code. I agree with everything he says and believe this is an important video to watch.

posted by Matt Snider at 11:47 am  

Tuesday, May 8, 2007

Prototype vs. YUI round 1: OOP Architecture

First, let’s make sure we are all using the same Frameworks, because these teams have been cranking out changes faster than you can keep up with them. This discussion will use the stable release of Prototype 1.5.1 and YUI 2.2.0. We will be analyzing the speed of creating small dummy objects to get an idea of which approach is better. Before, starting, I’d like to take a moment to thank the YUI guys for following rigorous coding standards and well documenting their code. I don’t know what high-horse the Prototype guys are riding, but there code is sloppy and it doesn’t compress well. Consequently, I have taken some time to clean up the prototype code (added semi colons, {} all statements, and ran jsmin): uncompressed and minified.

In the Prototype Framework you create Objects using the ‘Class.create()’ method. This basically attaches a function to your Object, that will execute the ‘initialize’ method you attach to the Object’s ‘prototype’ Object with all the variables you passed into the constructor. That’s a mouth full and a little hard to grasp textually, here is an example:

var PrototypeObject = Class.create();
PrototypeObject.prototype = {
initialize: function(v1, v2) {
// my initialization code
this.v1 = v1;
this.v2 = v2;
},
testFunction: function() {
alert(this.v1);
}
};
// to use
var someVariable = new PrototypeObject (v1, v2);
someVariable.testFunction();

The ’someVariable’ Object will contain all the functions and variables attached to ‘PrototypeObject.prototype’, including the initialize function. When I used this OOP Architecture, I often design the initialize function in such a way that it could be called again later to reset the object. This example illustrates how you can pass variables into the constructor and set them internally so that other function, like ‘testFunction’ can access the v1 variable, because it is attached to the ‘this’ keyword Object. You can extend these Object indefinitely, declare addition Objects inside, and do any number of customizations. However, I find that these Objects become larger than they need to be and are often difficult to follow.

In the YUI Framework you create Objects by executing a Function that contains ‘private’ like variables accessible only in the scope of the Function or through Closures in a returned Object. Again, difficult to describe textually; here is an example:

var YUIObject = function(v1, v2) {
var v1 = v1;
var v2 = v2;
return {
testFunction: function() {
alert(v1);
}
}
};
// to use
var someVariable = new YUIObject (v1, v2);
someVariable.testFunction();

So, this Object basically does the same thing as the PrototypeObject. The constructor call, instantiates the Function YUIObject, passing in two variables. Inside the scope of the Function those variables are redeclared to attach to the Function scope. Then the function returns an Object that ’someVariable’ will be set to. The ‘testFunction’ has access to v1 and v2 inside the Function scope because of Closures. For me this Architecture is easier to read and simpler to use, so I have built most of my Objects this way. The downside is that Closures leak memory like sieves in IE, if you are not careful.

To wrap up our discussion, I have created a page where you can compare the run times of the different instantiation. Unfortunately, JavaScript run-times aren’t very accurate and depend on the idle time of your computer. Having run it many times though in many browsers, I can summarize that on average the initialization of the YUI-type Objects is 35-45% faster than the Prototype Objects. Although, we’re talking about fractions of a millisecond, so you’re only going to notice this when you are creating thousands of Objects.

http://mattsnider.com/PrototypeVsYUITest.html

posted by Matt Snider at 8:20 pm  

Sunday, April 8, 2007

True, Truthy, WTF

As you probably know, JavaScript has keywords for true and false. These keywords are of the quasi-type ‘boolean’ and can be detected with my isBoolean() function that uses the ‘typeof’ keyword. What you may not know is that JavaScript, like many C-style derived languages, has the concepts of truthy and falsy. This concept is important because most of the JavaScript Frameworks, which we will soon be analyzing, make use of this feature.

These are non-boolean expressions that can be treated as a boolean value. The number zero is falsy, and any other number is truthy. Equally for strings, an empty string is falsy, and a non-empty string is truthy.

from TruthyFalsyAndTypeCasting

For an in-depth look at the concept ‘truthy’ vs the ‘keyword’ true, I created this test page: False Vs. Falsy Test Page

The best practice approach, is to use the keywords true and false, and try to avoid code that uses 0 and 1 for the purposes of truthy and falsy. It is acceptable to use truthi-/falsiness to determine if a variable does not have a value:
var obj;
if (obj) {
// do something
}
else {
// error management code
}

posted by Matt Snider at 5:49 pm  

Powered by WordPress