You have a massive array of items that needs to be transformed into an HTML list without causing the user any grief. There are a couple common ways of doing this:
Note: I’m not even going to bother covering direct DOM manipulation for every list item because that’d be plain stupid!
#1 – Step-by-step string concat
Not the slowest method that exists but probably the most common:
var arr = ['item 1', 'item 2', 'item 3', ...], list = ''; for (var i = 0, l = arr.length; i < l; i++) { list += '<li>' + arr[i] + '</li>'; } list = '<ul>' + list + '</ul>'; |
Don’t use this. It’s inefficient, slow and ugly!
#2 – Step-by-step array pushing
var arr = ['item 1', 'item 2', 'item 3', ...], list = []; for (var i = 0, l = arr.length; i < l; i++) { list[list.length] = '<li>' + arr[i] + '</li>'; } list = '<ul>' + list.join('') + '</ul>'; |
Slightly faster than string concatenation but still not perfect…
#3 – The holy grail!
var arr = ['item 1', 'item 2', 'item 3', ...]; var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>'; |
I won’t bore you with benchmarks; you’ll just have to believe me (or test for yourself) – this is by far the fastest method!
Using native methods (like join()
), regardless of what’s going on behind the abstraction layer, is usually much faster than any non-native alternative.
Browser benchmarks
Due to a request and my own curiousity I’ve conducted a quick benchmarking test. Each method was tested with a 130-item array, the length of each item varied so any optimizations on the browser’s part would not be effective. Each method was tested 1000 times; the results below show how long each browser took to complete each method 1000 times:
“String concat” (ms) | “Array pushing” (ms) | “Native join()” (ms) | |
---|---|---|---|
Firefox 3 | 147 | 148 | 65 |
Opera 9 | 172 | 125 | 78 |
IE 7 | 500 | 2297 | 79 |
Chrome 2 | 63 | 88 | 72 |
Safari 4b | 146 | 141 | 60 |
Averages | 205 | 559 | 70 |
Surprisingly, string concatenation came out much faster than “array pushing” on average. It seems IE7 optimizes for lengthy string operations but doesn’t care much for arrays. Also, Google Chrome performed oddly; the “string concatenation” method was quicker than the “native join()”… I’m not too sure what’s going on there! Anyway, the results were mostly predictable, and, of course, “native join()” came out on top!
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
I’ve always known it’s best to push off as much work as possible to outside of the script, but I wouldn’t have thought to join with the close+begin tags like that. Very nice.
Nice post, never really had to do this in javascript too much (most markup is generated server side), but interesting to see a real-life use of join().
Haven’t used join() in javascript, but I have experience with list functions like that in haskell and I see its usefulness here.
Thanks so much for this short but useful tip, James. Your articles are my milk in the morning.
Ban.
Be real good to see the actual benchmarks, especially x-browser.
Thanks for the comments! 🙂
@redsquare, just added some benchmarks.
what about doing:
That way, if the array is empty, you dont get an empty [li] in the ul !
Could you add this method to your bench?
@Matthieu: You could just use a ternary operator.
How do you benchmark?
Cheers James, what happened to our best friend ie6!
Should be faster than any method above although maybe not as elegant
It seems my method is not faster:
IE 8
Concat: 161
Arraypush: 320
HolyGrail: 72
My method: 263
FireFox 3
Concat: 135
Arraypush: 127
HolyGrail: 39
My method: 140
How are you guys testing?
Here’s how I tested: http://pastie.org/499582
@redsquare, IE6 uses the same JS engine as IE7 – the results would be very similar.
Sweet thanks!
I’d bet the developers of Chrome’s JS engine actually optimized the “ugly” method knowing that as you stated, it probably is the most common.