Tag Archives: jQuery

The speed of jQuery.append(…)

I’ve been doing some JavaScript performance optimization recently and I thought I’d share some of my findings regarding jQuery.

The project I’m working involves creating large DOM trees of elements from data, and I’ve been trying to speed things up. Initially I was using jQuery.append(...) combined with document.createElement(...) in something along these lines:

var foo = $(document.createElement("span")).attr("bar", "baz");
$(parent).append(foo);

The reason for this style is because I want to be able to keep around references to the created object so I can use it later and not be forced to use selectors.

While doing some profiling, I became concerned that the append call was taking too much time, so I did some testing. Some articles I’ve read indicated that it was better to do string concatenation to create a massive strings of the elements that you wanted to create and the use a single jQuery.append(...) call to create the elements at the end. I tested that scenario as well.

My test code:

(function() {
	var start = new Date();
	var root = document.createElement("span");
	for(var i = 0; i < 100000; i++) {
		root.appendChild(document.createElement("span"));
	}
	var end = new Date();
	alert("Raw appendChild: " + (end.valueOf() - start.valueOf()));
})();

(function() {
	var start = new Date();
	var root = $(document.createElement("span"));
	for(var i = 0; i < 100000; i++) {
		root.append(document.createElement("span"));
	}
	var end = new Date();
	alert("jQuery append: " + (end.valueOf() - start.valueOf()));
})();

(function() {
	var start = new Date();
	var root = $(document.createElement("span"));
	var inners = "";
	for(var i = 0; i < 100000; i++) {
		inners += "";
	}
	root.append(inners);
	var end = new Date();
	alert("jQuery from string: " + (end.valueOf() - start.valueOf()));
})();


(function() {  
    var start = new Date();  
    var root = document.createElement("span");
    var inners = "";  
    for(var i = 0; i < 100000; i++) {  
        inners += "";  
    }  
    root.innerHTML = inners;
    var end = new Date();  
    alert("innerHTML: " + (end.valueOf() - start.valueOf()));
})();

Run Code

The numbers I get are as follows on my Mac in Firefox are as follows (creating 10k span elements).

Raw appendChild: 304 ms
jQuery append: 5492 ms
Concatenated string (jQuery Append): 6040 ms
Concatenated string (raw innerHTML): 208 ms

My results were somewhat inconsistent. Initially when I was running this test I did see jQuery append with the concatenated string to be faster, but when running tests later, it was a bit slower. In general, I think the conclusion of the article is correct. String concatination is better than many calls to jQuery.append(...), but it doesn’t hold a candle to just doing the raw DOM manipulations. This makes sense since jQuery still has to parse the string you give it (it doesn’t feed it raw into the innerHTML) and then call the raw DOM methods directly. Lesson learned.

jQuery Plugins

Yesterday I spent several hours going through the UI jQuery plugins and compiled a list of the most interesting to me. Bear in mind that in many cases interesting to me is driven by the fact that I work with scheduling software.

  • FullCalendar month-view calendar that supports drag and drop of events (demo)
  • AutoScroll script to automatically scroll an element as you near an edge
  • jCal large, multi-day day picker control
  • jEditable control that allows arbitrary text to edited inline when clicked
  • jGrowl plugin to create a Growl-like effect on a web page
  • Growl another plugin to create a Growl-like effect on a web page
  • DynaTree dynamic tree view (demo)
  • jScrollPane javascript scroll bars (demo)
  • Purr yet another Grow-like effect on a web page. This one has the nicest visual presentation of those listed.(demo)
  • QuickSearch javascript search field that eliminates non-matching elements from a table
  • SemanticTabs jQuery tabs
  • uiTableFilter filters elements of a table based on a search field
  • Throbber jQuery loading circle (demo)
  • TimePicker jQuery timepicker

Labelify for ASP.NET 1.1

If you haven’t tried it already, Labelify is a great jQuery plugin that gives text fields default value labels so that you can either provide hints to your users, or to save space and not have separate labels for each field.

The plugin works by setting the contents of the text field to the title text and setting it to a special style whenever the field holds its default value. As soon as the field receives focus, the default value is removed and the user is free to type whatever they like.

One problem that must be overcome is that the script must remove these title values from the fields before the form gets submitted if the user doesn’t type something else in the fields. If it doesn’t the field submits bogus data, and may also cause the form to not pass validation. The script solves this problem by listening to the submit event on the form, and removing any remaining values that it had placed in the text fields when the page was loaded. The problem is, when a form is submitted via the submit(); method in Javascript, the event does not fire. This can be a big problem in ASP.NET because many of the controls auto-post back, which involves submitting the form via JavaScript.

To correct this problem, you can attach an event handler to a relevant event on the items in the page that could trigger a problematic post-back so that interacting with that item will explicitly trigger the submit event in jQuery. For example, the following code will respond to the click event on all ASP.NET link buttons:

// Hack to allow the ASP.NET link buttons to work with our labelify labels...
$("a[href^=javascript:__doPostBack]").click(function() { 
  $(this).parents("form").triggerHandler("submit"); 
});

As second problem encountered in ASP.NET is that post-backs will cause the page to be re-rendered, sometimes with text pre-populated in the text fields from before the post-back was initiated. This text is considered the default value for these fields, which is a problem because labelify displays the title text whenever the text field’s value matches its default value.

To get around this, I created an updated version of labelify that will allow you to specify that you only want label text to be displayed if the value of the text field is empty, and have it ignore the default value for the field.

To use this updated version, the original Javascript to create the labelified fields would go from this:

$(document).ready(function(){
  $(":text").labelify();
});

to this:

$(document).ready(function(){
  $(":text").labelify({ replaceEmptyOnly: true });
});