Sitting on jQuery's support mailing list I noticed that developers use jQuery with huge data sets and their code becomes very slow. Examples would be generating very long tables with a lot of rows using AJAX to get JSON data. Or iterating through a long (very long) list of data, etc.
So I compiled a list of 5 easy tips on how to improve your code performance while working with huge data sets in jQuery.
- Use JavaScript native
for()
loop instead of jQuery's$.each()
helper function.
Native browser functions are always faster then any other helper functions that were built to add an abstraction layer. In case you are looping through an object that you have received as JSON, I highly recommend you rewrite your JSON to contain an array rather than an object.
- Do NOT append an element to the DOM in your loop.
This one is probably one of the most important tips that will significantly improve your code performance. It is so important that I will repeat myself. Do not append a new element to the DOM in your loop statement. Instead store it in a variable as text and append it to the DOM after your loop finishes like this:
// DO NOT DO THIS for (var i=0; i<=rows.length; i++) { $('#myTable').append('<tr><td>'+rows[i]+'</td></tr>'); } // INSTEAD DO THIS var tmp = ''; for (var i=0; i<=rows.length; i++) { tmp += '<tr><td>'+rows[i]+'</td></tr>'; } $('#myTable').append(tmp);
- If you have a lot of elements to be inserted into the DOM, surround them with a parent element for better performance.
When you have a lot of elements to insert into the DOM tree it takes time to add them all. Somehow adding one element with 1000 children is faster than adding 1000 children separately. You can search this site for performance tests that prove it.
So, to improve our previous example's performance let's cover<tr>
's with<tbody>
tag like this:
var tmp = '<tbody>'; for (var i=0; i<=rows.length; i++) { tmp += '<tr><td>'+rows[i]+'</td></tr>'; } tmp += '</tbody>'; $('#myTable').append(tmp);
- Don't use string concatenation, instead use array's
join()
method for a very long strings.
var tmp = []; tmp[0] = '<tbody>'; for (var i=1; i<=rows.length; i++) { tmp[i] = '<tr><td>'+rows[i-1]+'</td></tr>'; } tmp[tmp.length] = '</tbody>'; $('#myTable').append(tmp.join(''));
- And the last but not least use setTimeout() function for your long list looping and concatenation functions.
This will make sure that page does not freeze while it loops through the long list of data and lets users to work with your page meanwhile.It was well mentioned in comments that setTimeout() function should be used to split your code processing into little chunks so your browser does not freeze up like this:
function myFunk(data){ // do processing if(!has_finished) setTimeout("myFunk()", 100); }
The last tip is useless. Setting a 0 timeout will do nothing but delay the execution to the next processing cycle. What is usually done is splitting the function to execute in blocks, say 100 loops at a time, with a 20ms interval between them. That can really prevent browser freezes.
ReplyDeleteThanking in your post the folks from the mailing list who started the whole discussion and helped you learn these tricks is always nice.
Great! I'll be applying these tips on my website soon!
ReplyDeleteQuestion on tip #5...
ReplyDeleteWhen you say to set a timeout, are you referring only to code called onLoad? Or do you mean anytime a long method will be called? And if it is the latter, why does this work?
Regarding #3 Id say it could be better to append td's every Nth iteration so that the table builds up progresivly to the user, instead of the browser doing nothing (to the user) and after some seconds the whole table pops up.
ReplyDeleteExample:
var tmp = [];
var n = 10; //adjust n depending on rows.length;
var $target = $('#myTable');
for (var i=0; i<=rows.length; i++)
{
tmp.push('[tr][td]',rows[i],[/td][/tr]');
if(i % n == 0) {
$target.append(tmp.join(''));
tmp = [];
}
}
Had to replace <> for [] coz of blogspots crappy tag support.
for The json aspect, you could use the javascript's for in looping.. which is great for objects as well as arrays..
ReplyDeleteeg:
var json = {item:'1',key:'222'};
for(key in json) {
var value = json[key];
}
@misskitty
ReplyDelete"for The json aspect, you could use the javascript's for in looping.. which is great for objects as well as arrays.."
not exactly - a for...in loop works in a slightly different manner that a for loop. A for...in loop, for example, does not guarantee iteration through the properties in any specific order, and can dredge up undesired properties from the object's prototype. Generally, the purpose of using an array is to insure numeric iteration in order, so a for...in loop will likely cause problems.
Now, that being said, a for loop only iterates through the enumerable properties, so using it on an object will likely cause issues as well. In reality, using a for loop for ARRAYS ONLY and a for...in loop for OBJECTS ONLY is the safest and most reliable technique
@anon "April 16, 2009 10:59 AM"
ReplyDeleteThe idea that objects properties will come out in a random order is a bit of a misunderstanding. The truth is that order is kept in the stored properties, and the order that they're accessed in is the order that they're added in: first-in-first-out. If you have control over the way they're added to the object, then you can guarantee the order of the output. Otherwise, yes, an array is a good idea. Also, you don't have to worry about properties coming up from the prototype chain if you use the hasOwnProperty() method. That is the very purpose of that method.
Thanks for these... i was appending over a 100 items separately in a loop - how stupid! Tip #2 just saved me quite a lot of time in some circumstances.
ReplyDeleteCheers!
I was like breaking all these rules in an ajax search script I built. I fixed them and now it works brilliantly fast. Thanks!
ReplyDeleteAbout #2 and #3: I suggest using a documentFragment instead creating a string, then appending the whole documentFragment in the DOM
ReplyDeleteGood ones mate. I have also linked to yours from my blog post below where I am trying to collect the most useful and common jQuery code snippets for JavaScript over the web. Here is the title and the link to the jQuery link compilation endeavor:
ReplyDeleteUltimate collection of top jQuery tutorials, tips-tricks and techniques to improve performance
http://technosiastic.wordpress.com/2009/09/24/collection-of-top-jquery-tutorials-tips-tricks-techniques-to-improve-performance/
Thanks for the article. I hope you allow me to introduce a few feedbacks:
ReplyDelete* For those who don't understand the performance's issues with DOM, the benchmark from Peter-Paul Koch is perfect:
http://www.quirksmode.org/dom/innerhtml.html. The faster method is to push strings into an array, then join array, and finally use innerHTML to update the DOM.
* @Andreas: Depending from your case. While the table is loading, some users may read informations, and others may start interacting with it ( clicking if links are provided for example, etc...). Take care with "progressive display"
* I may understand what the last section means, but yes it seems wrong.
Some good technical links:
How JavaScript Timers Work, by John Resig - http://ejohn.org/blog/how-javascript-timers-work/
Asynchronous innerHTML, by James Padolsey - http://james.padolsey.com/javascript/asynchronous-innerhtml/
Cheers
nice tips its useful to me
ReplyDeleteGood post
ReplyDeleteTip 2... Absolute Magic. All I can say is thanks, you've made my day
ReplyDeleteWell some of these are a now a bit outdated as we have 1.4.2 version. It's been speed improved a lot compared to the last most used version 1.3.2 (I think it was)
ReplyDeletei have performance problem,now i replaced $.each by for loop, performance increases markedly.
ReplyDeleteThank you !