I posted recently about a drag and drop plugin that I had created in the name of performance, but this was not the only performance bottleneck that I had to overcome in my application. As I said before, my application has two lists, one of which depends on the selection of the other for its content. Whenever the selection of the first list changes, the content of the other list updates, often with several hundred items. As I said before, one of the performance issues that I had, was the time it took to bind event listeners to all of those DOM elements for drag and drop. I solved this though event delegation. This change dramatically increased performance, but additional optimizations were still needed. Unfortunately, the issues were mostly beyond my control since the DOM was the source of the problem. Here is my original code.
$("#first-list li").live("mousedown", function() {
$("#second-list").empty();
$.each(content, function(i) {
$("<li>").text(this.name).appendTo("#second-list");
});
});
As this code shows, every time a user clicks on a list item in the first list, all of the items in the second list were removed using the jQuery.empty() function, and all of the items in the content array are appended to the second list.
So why is this slow?
This looks like pretty normal jQuery code and it works great until you have a lot of elements to append all at once. The reason that appending elements is slow, is because the browser must reflow the entire page every time an element is appended. Reflowing is the process that the browser’s layout manager goes through every time something changes size, or is added or removed from the page. During the process, the browser must recalculate the position and size of all of the elements on the page and then repaint it. Since reflowing occurs after appending each individual item to the DOM, performance can really take a hit.
The solution
The solution to this problem is to force the browser to reflow only once, and an unfortunate side effect is less simple looking code.
$("#first-list li").live("mousedown", function(e) {
var html = [],
len = content.length,
i = 0;
for(var j=0; j<len; j++) {
html[i++] = "<li>";
html[i++] = content[j].name;
html[i++] = "</li>";
}
$("#second-list").html("<div>" + html.join('') + "</div>");
});
In this code, instead of using jQuery to create and append elements to the DOM, we actually create a long string of all of the elements that we want to append in memory, and then set it as the innerHTML of the second list. I have further optimized the code so that it actually creates an array of strings and then joins them, which is faster than doing string concatenation in most browsers. I have also wrapped all of the list items in a single DIV, which speeds up the browser because it can insert the elements as a block instead of individually.
So how does this perform?
Appending elements all at once performs much better than using jQuery to append the elements as they are being created, which would be expected. In my informal tests appending 500 elements, the grouped performance is often double the individual speed.
Conclusion
Performance is a very big issue if you are writing large scale applications, and it is unfortunate that the browser platform is slow in such a key area. That is why hacks like this exist: to artificially make things faster. It is my hope that browser makers will step up to the plate and make one of the most important parts of the browser faster for programmers, and most importantly for users. Until then however, we as developers need to get around these performance issues so that the experience that users have with web applications is a positive one. Performance is one of the final hurdles of browser based apps which I firmly believe are the future of computing.
December 11, 2009 at 8:00 pm
Social comments and analytics for this post…
This post was mentioned on Twitter by gluecode: RT @elijahmanor: “jQuery DOM Manipulation At Lighting Speeds” by Devon Govett #tech #jquery http://j.mp/5K34aa…
December 12, 2009 at 6:11 pm
[...] many other places. Speed is an important thing to web application developers which I have blogged about in the past. In my case, I was writing a highly dynamic app with jQuery, and the empty function was [...]
December 20, 2009 at 10:54 am
Nice article. Much appreciated. Thanks a lot for sharing.
June 18, 2010 at 2:06 pm
How about something like this as a compromise between pretty code and “lightening speeds”:
$(“#first-list li”).live(“mousedown”, function() {
$(“#second-list”).empty();
var html = “”;
$.each(content, function(i) {
html += $(“”).text(this.name).html();
});
$(“#second-list”).html(html);
});
September 13, 2011 at 8:52 pm
anti-corporate news…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 14, 2011 at 3:35 am
Hotels In Mumbai…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 16, 2011 at 12:38 pm
New Orleans advertising…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 17, 2011 at 9:27 am
toko cctv…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 23, 2011 at 3:25 am
free professional kids swimming lessons…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 23, 2011 at 9:09 pm
jingle bells sheet music…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
September 27, 2011 at 7:37 pm
Safe harbor 401k rules…
[...]jQuery DOM Manipulation At Lightning Speeds « Devon Govett[...]…
March 26, 2013 at 10:07 pm
Heya i am for the first time here. I came across
this board and I find It truly useful & it helped me
out a lot. I hope to give something back and help others like you aided me.