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 = $('').html(item).attr('name','pieTD'); var newTr = $(''); newTr.append(newTd); $('table').append(newTr); });[/js]

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 = '' + item + ''; $('table').append(newTr); });[/js]

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!

[js]var arr = reallyLongArray; var textToInsert = ''; $.each(arr, function(count, item) { textToInsert += '' + item + ''; }); $('table').append(textToInsert);[/js]

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++] = ''; textToInsert[i++] = item; textToInsert[i++] = ''; }); $('table').append(textToInsert.join(''));[/js]

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++] = ''; textToInsert[i++] = arr[a]; textToInsert[i++] = ' < /tr>' ; } $('table').append(textToInsert.join(''));[/js]

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 faster
Next 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 .2755 
array.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 .094 
array.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