43,439 reasons to use append() correctly
The .append()
method is perhaps the most misused of all jQuery methods. While an extremely useful and easy method to work with, it dramatically affects the performance of your page. When misused, the .append()
method can cripple your JavaScript code's performance. When used well, it'll keep your script humming along.
Here is a typical example of append misuse:
[js]var arr = reallyLongArray; $.each(arr, function(count, item) { var newTd = $('Ran Once: Profile (308.697ms, 17861 calls, Firefox 3.06)
Ran in a for loop 100 times: Profile (51782.295ms, 1805100 calls)
If you're coming from Prototype to jQuery, chances are this looks quite natural to you. It's the way that Prototype does node creation/insertion, but with a little bit of jQuery chaining thrown in. Let's see how we can improve this.
[js]var arr = reallyLongArray; $.each(arr, function(count, item) { var newTr = 'Ran Once: Profile (107.458ms, 3991 calls, Firefox 3.06)
Loop of 100: Profile (21641.336ms, 399100 calls)
Whoa! Nearly a 3x difference, and much simpler to look at. jQuery can take more then one node at a time and create them all at once. You also don't need to wrap it in $()
before appending it. jQuery knows what to do. But wait, there's more!
Ran Once: Profile (30.792ms, 778 calls, Firefox 3.06)
Loop of 100: Profile (8505.37ms, 77800 calls)
Taking full advantage of the ability of jQuery to insert a chunk of html in a string means only having to call insert once. It's much quicker, with an approximately 9-10x speed increase from the initial algorithm! This will be fast enough for 95% of cases, but for strings with lots of string concatenation… Wait, there's more!
[js]var arr = reallyLongArray; var textToInsert = []; var i = 0; $.each(arr, function(count, item) { textToInsert[i++] = 'Credit for this one goes to Michael Geary
Ran Once: Profile (29.724ms, 778 calls, Firefox 3.06)
Loop of 100: Profile (8298.699ms, 77800 calls)
This version is a bit harder to understand, as the html is not in an easy to read format, and the results vary by browser* (see below for further analysis), but in most current and next generation browsers, adding to an array and joining it into a string at the end is quicker then doing string concatenations. So, if you are looping through a large number of string concatenation and need some more speed, you should consider this method. So, now we're done, right? This is as blazingly fast as we can get it? Not quite.
[js]var arr = reallyLongArray; var textToInsert = []; var i = 0; var length = arr.length; for (var a = 0; a < length; a += 1) { textToInsert[i++] = 'Ran Once: Profile (29.72ms, 587 calls, Firefox 3.06)
Loop of 100: Profile (8274.359ms, 58700 calls)
As handy as .each()
is for small loops, calling a function that executes a callback inside of a loop will always be slower than just creating the loop in pure JavaScript. The difference here isn't so noticeable because the array I used only has a length of 190, but for really large loops it makes a measurable difference. In addition, while the difference is very slight (.000062 vs .000037 ms over 1,000,000 empty loops), it is quicker to save the array length in a variable and use it instead of looking up an object property every loop (thanks Karl Swedberg!).
For most of your uses, the method of creating one really long string and appending it at the end will be the best choice, as it makes the best use of the trade offs of code legibility, ease of programming, and speed.
Please tell me your methods for speeding up array loops or appending using jQuery in the comments below.
For completeness, I used jQuery 1.3.2, Firebug 1.3.3 and Fireunit 1.0a1 on Firefox 3.06 on a Mac to do the profiling. And the reallyLongArray I used was:
var arr = [1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc', 'cada',
'2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc',
'cada', '2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6,
'ffadscdasc', 'cada', '2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as',
6, 2, 3, 6, 'ffadscdasc', 'cada', '2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5,
'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc', 'cada', '2wd', 3, 7, 3, 2, 'sdf', 1,
2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc', 'cada', '2wd', 3, 7, 3,
2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc', 'cada', '2wd',
3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6, 'ffadscdasc',
'cada', '2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as', 6, 2, 3, 6,
'ffadscdasc', 'cada', '2wd', 3, 7, 3, 2, 'sdf', 1, 2, 3, 4, 5, 'adsf', 'as',
6, 2, 3, 6, 'ffadscdasc', 'cada', '2wd', 3, 7, 3, 2, 'sdf'];
Further analysis of += vs array.join, broken down by browser
---------------Current gen Browsers
FF3 array.join is ~2x faster Safari 3 array.join ~1.5x faster Opera 9 += ~3x faster ie6 array.join ~6x faster ie7 array.join ~4x fasterNext gen browsers
FF3.1 += array.join equal in speed Chrome += ~1.25x faster IE8 array.join ~1.6x faster Webkit array.join ~2x faster
Raw results
(2709 characters) 9 character string, added 300 times. Looped 100,000 times and averaged. +=FF3.06 .2046 - .25835 .1849 .17045 Opera9 .1256 - .12795 .12678 .12197 Safari3 .1368 - .14875 .13128 .13032 IE6 3.359 - took forever, crashed/froze browser sometimes IE7 1.68985 - took forever FF3.1 .0735 - .0813 .0710 .0683 Chrome .0256 - .025 .021 .031 Webkit .0655 - .06602 .06527 .06533 IE8 .2921 - .3104 .2905 .2755array.join - called 300 times, looped 100,000 times and averaged.
FF3.06 .1056 - .10701 .10439 .10541 Opera9 .3355 - .33091 .31484 .36066 Safari3 .0813 - .08128 .08089 .08172 IE6 .5086 - .50609 .50829 .51156 IE7 .4101 - .42265 .38875 .41891 FF3.1 .0743 - .0766 .0721 .0741 Chrome .0315 - .03 .048 .027 .021 Webkit .0300 - .02962 .03123 .02937 IE8 .1832 - .1841.1872 .1872 .1741(35109 character string) 351 character string added to a nine character string 100 times, looped 1000 times and averaged +=
FF3.06 1.81 - 1.897 2.015 1.518 Opera9 .6306 - .631 .634 .627 Safari3 .9156 - .931 .884 .932 IE6 65.657 - 58.078 56.641 89.313 58.594 // I can see where += was a huge problem then. IE7 .9316 - .937 .934 .924 FF3.1 .9141 - .47 .663 1.123 .705 1.165 1.361 .698 1.128 Chrome .031 - .039 .024 .02 .041 Webkit .996 - .991 1.014 .983 IE8 .09 - .094 .094 .078 .094array.join the above
FF3.06 .9143 - .923 .83 .99 Opera9 1.773 - 1.832 1.747 1.741 Safari3 .2106 - .249 .19 .193 IE6 .8368 - 2 .375 .469 2.078 .343 .36 .735 .625 .547 IE7 .4428 - .531 .516 .391 .375 .438 .406 .609 FF3.1 1.070 - 1.221 .678 1.366 1.508 .665 1.423 .631 Chrome .0318 - .02 .022 .059 .026 Webkit .1773 - .175 .176 .181 IE8 .4820 - .14 1.141 .156 .609 .625 .328 .375