Improving jQuery performance on element-heavy pages

I’ve been working on the client-side validation for our new BOS2 survey service. We need to validate all form fields on the page both as the user interacts with each field, but also before page submission. On the server-side we also do a full validation check, but if we can do all this validation locally this will provide a more responsive experience for the user as well as stop invalid submissions which will help reduce the load on the server.

Normally you would’t need to bother optimising jQuery code as it rarely effects performance in a noticeable fashion, but as the numbers of elements grow then the delay in processing each item can become more obvious. Our survey pages can contain some pretty complicated forms (especially with groups of questions arranged in a grid-like pattern) so the numbers of individual fields can easily get into the hundreds. When the respondent hits the submit button, we need to run a validation check over each input element in the page, and if invalid, update the UI  to highlight these problems. This process was taking well over a second to run when we had around 250 fields on the page which was causing a noticeable delay.

I played around with various optimisation techniques (reducing UI updates, caching frequently accessed elements etc) and discovered a number of jQuery-specific mechanisms for increasing the speed of our validation (which helped reduced our submit handler processing to around 350-500ms) and I thought these might be interesting to others.

1. Improve jQuery selector performance

There are many different ways to identify elements using jQuery. I found when using class-based selectors it was better to obtain the parent and then use a .find() call rather then combine the selectors into a single query. So rather than:

$(".grid input[type=radio],.grid input[type=checkbox]");

a much quicker alternative is to use the following:

$(".grid").find("input[type=radio], input[type=checkbox]");

Note that the affect is reversed if your using tag names rather then classnames; also the speed of various selectors will depend on the specific structure of the elements on your page.

2. Stop event bubbling

An easy one to miss (as I did) – by default jQuery events will bubble up to DOM tree so if you don’t want this (which can drastically reduce the number of events being processed), remember to disable this feature.

$('[selector]').on('my-event', function(){
/* do something */
return false; // stop event propagation
});

3. Reduce the use of .trigger()

I had been naïvely calling trigger on all our form fields prior to submission. The trigger method adds a large amount of processing overhead so a better alternative is to assign functions directly on the elements and then call them directly.

So rather then the following:

$('[selector]').on('my-event', function(){ /* do something */ return false; });
// sometime later
$('[selector]').trigger('my-event');

Switch to assigning the function directly on your elements and then calling the function when you need to.

$('[selector]').each(function(){ this.myEvent = function() {/* do something */});
// sometime later
$('[selector]').each(function(){ this.myEvent(); });

 

If you want to see the effects of these for yourself, I created the following JSFiddle demonstration which shows examples of each in action.