Faster JavaScript with jQuery
August 5th, 2007As you start to build more AJAX features into your application you will be writing more and more JavaScript. Even though we are getting more tool support for JavaScript, especially with Visual Studio 2008, it can still be difficult to work with JavaScript because of browser differences. Even changes between Internet Explorer 6 and 7 can be troublesome. To minimize these problems I have been leveraging different JavaScript libraries which provide a rich set of features that have already handled the cross-browser issues. My favorite has become jQuery for multiple reasons.
The main reason I like jQuery is the fact that it is designed to do more with less code. The programming model lends itself to very compact code that does a lot for you. It also has a rich querying model that allows you to use CSS selectors to find elements within a web page and apply various changes on those elements. And another great reason to use it is the fact that it allows you to write much faster JavaScript. The jQuery model allows you to chain methods together. Each call to jQuery starts with a query like $('div.content') that will match all div blocks in the with content set as the class name. The method returns a jQuery object which can then be used to call another method, like addClass('Highlight') that will add Highlight as a class name to all of the matched elements. It will then return the jQuery object again for another method to run a jQuery method. Chaining the calls allows the same objects to be used over and over so you can avoid the overhead of creating objects which is expensive.
I created a test with three scenarios to try out the speed of using jQuery in different ways. The third scenario is the slowest because it separates each method call with a separate query.
Third Scenario - Separate Queries - Slowest
The second scenario is just a little faster because just runs the query once and chains the calls together but it uses the each method which passes the individual matches to methods that do the same action as the third scenario.
Second Scenario - Using Each - Slightly Faster
Finally the first scenario simply inlines all of the method calls with the single query and it runs dramatically faster than the others.
First Scenario - Inline Chaining - Fastest
During my testing I found that consecutive calls took longer to run. In this test I create a table for each of the three scenarios and when the test is run the blocks holding the tables are emptied and rebuilt. This causes the values and events that were bound to the elements in the table to disappear. In jQuery however, it still has an array holding onto elements that have been bound with events. When the elements disappear this array suddenly is filled with null values and consecutive calls to run the test fill the array with more nulls which takes more time for jQuery to run because it has to iterate through the array each time. I logged a ticket with the jQuery project website with the following solution. Basically the methods below loop over the array holding these element references and pulls out the items that are not null and sets that as the new array. Then in my code I run the method to clean the array after the tables have been deleted. Now the consecutive calls run in relatively the same time without progressively taking longer with each test run.
Cleaning the Event List
You can see the full test yourself. I created the test because I am using jQuery with ASP.NET AJAX pages which use an UpdatePanel that replaces sections of the page without any concern for what events are bound to the elements in the replaced content. Now I can call the clean method as each update panel is loaded to ensure the event list stays nice and trim.
Why the Funny Function Names?
You may have noticed that each method name is prefixed with $cm_. I do this to avoid naming conflicts since there are no real namespaces in JavaScript. But you can create objects which contain your functions. What I am doing here is naming the functions something I know is very likely to be unique and then I construct the object with these functions using the function references. Organizing the object this way allows me to see what is in the object at a glance since I can see it all in a compact way. It also allows me to effectively have private methods because I call those methods internally but do not add the reference to the object. I am borrowing this idea from the ASP.NET AJAX client-side code.


