String builder benchmark test
From Trephine
[subscribe] Recent blog entries
- Simple prototypal inheritance new!
- Adventures in Rhino - setters and getters
- Site improvements - fighting with Disqus
- JavaScript task chaining
- JavaScript string building benchmarks
- Efficient JavaScript string building
- Alternative JavaScript worker thread API
- Implementing JavaScript worker threads
- Thread safe DOM manipulation
- Site improvements - CSS sprites
- Trephine worker threads made easy
- Pitfalls of multithreaded browser development
- Site improvements - reducing dependencies
- The unsplittability of XML
Live Demos
String builder benchmark test
A simple suite to benchmark the five implementations of buildList() in Efficient JavaScript string building.
Results are discussed in the article JavaScript string building benchmarks.
You must have JavaScript enabled to run this benchmark.
// List of the 5 implementations var implementations = [ function buildList( /* list1, list2, ... */ ) { var buf = "<ul>\n"; // initialize buffer for (var i=0; i<arguments.length; i++) { // iterate over arguments var list = arguments[i]; // grab next list for (var j=0; j<list.length; j++) { // iterate over list buf += "<li>"; buf += list[j]; // append item to buffer buf += "</li>\n"; } } buf += "</ul>" // finalize buffer return buf; }, function buildList( /* list1, list2, ... */ ) { var buf = [ "<ul>\n" ]; // initialize array buffer for (var i=0; i<arguments.length; i++) { var list = arguments[i]; for (var j=0; j<list.length; j++) { buf.push( "<li>", list[j], "</li>\n" ); // append item to buffer } } buf.push( "</ul>" ); // finalize array buffer return buf.join(''); // concatenate and return }, function buildList( /* list1, list2, ... */ ) { var buf = [ "<ul>\n" ]; for (var i=0; i<arguments.length; i++) { var list = arguments[i]; for (var j=0; j<list.length; j++) { buf[buf.length] = "<li>"; // append <li> tags and buf[buf.length] = list[j]; // item to array buffer, utilizing buf[buf.length] = "</li>\n"; // primitive array assignment } } buf[buf.length] = "</ul>"; return buf.join(''); }, function buildList( /* list1, list2, ... */ ) { var buf = []; for (var i=0; i<arguments.length; i++) { var list = arguments[i]; buf[buf.length] = list.join( "</li>\n<li>" ); // join list, append to buf } if (!buf.length) return "<ul>\n</ul>"; // short-circuit if no items var last = buf.length-1; buf[0] = "<ul>\n<li>" + buf[0]; // add opening <ul> prefix buf[last] = buf[last] + "</li>\n</ul>"; // add trailing </ul> suffix return buf.join( "</li>\n<li>" ); // concatenate and return }, function buildList( /* list1, list2, ... */ ) { var size = 0; // initalize size counter for (var i=0, l=arguments.length; i<l; i++) { // iterate over arguments size += arguments[i].length; // add up all lists lengths } if (size==0) return "<ul></ul>"; // short-circuit if zero items var buf = new Array( size ), pos = 0; // initialize buffer and pos for (var i=0, l=arguments.length; i<l; i++) { // iterate over arguments var list = arguments[i]; // grab the next list for (var j=0, k=list.length; j<k; j++) { // iterate over list buf[pos++] = list[j]; // set buffer position to item } } buf[0] = "<ul>\n<li>" + buf[0]; // add opening <ul> prefix buf[size-1] += "</li>\n</ul>"; // add trailing </ul> suffix return buf.join("</li>\n<li>"); // concatenate and return } ]; // Short-hand names of implementations var names = [ 'string buffer', 'push array buffer', 'native assignment', 'direct join', 'pre-count buffer' ]; // Build data sets var data = { small: null, // 128x128 medium: null, // 256x256 large: null // 512x512 }, p = 7; for (var k in data) { var size = Math.pow( 2, p++ ); var list = new Array( size ), args = new Array( size ); for (var i=0; i<size; i++) list[i] = i; for (var i=0; i<size; i++) args[i] = list.slice(0); data[k] = args; } // Utility functions for setting status and adding data row var status = function(s) { document.getElementById('status').innerHTML = s; "<div class=\"notice\">" + s + "</div>"; }; var addRow = function(row) { var results = document.getElementById('results'); var tbody = results.getElementsByTagName('tbody')[0]; var tr = document.createElement('tr'); for (var i=0, l=row.length; i<l; i++) { var td = document.createElement('td'); td.appendChild(document.createTextNode(row[i])); tr.appendChild(td); } tbody.appendChild(tr); }; // Create task queue var tasks = [], iterations = 5; for (var i=0, l=implementations.length; i<l; i++) { (function( i, buildList, stat ){ for (var k in data) (function(k){ tasks.push( function(){ status( "<div class=\"notice\"><span class=\"spinner\"></span> " + "Running implementation " + ( i + 1 ) + " against " + k + " data set...</div>" ); var start = new Date(); for (var m=0; m<iterations; m++) buildList.apply( null, data[k] ); var end = new Date(); stat[k] = ( end.valueOf() - start.valueOf() ) / iterations; } ); })(k); tasks.push( function(){ var label = ( i + 1 ) + ". " + names[i]; addRow( [ label, stat.small, stat.medium, stat.large ] ); } ); })( i, implementations[i], {} ); } tasks.push( function(){ status( "<div class=\"success\">Benchmarks completed successfully</div>" ); } ); // Execute tasks sequentially var index = 0, chain = function(){ tasks[index++](); if (index<tasks.length) setTimeout( chain, 100 ); }; chain();
<table class="wikitable" id="results"> <thead> <th>implementation</th> <th>small (ms)</th> <th>medium (ms)</th> <th>large (ms)</th> </thead> <tbody></tbody> </table> <div id="status"></div>
.demotab .spinner { padding: 10px 10px; background: url("skins/common/images/spinner.gif"); background-position: center center; background-repeat: no-repeat; } .demotab td { border-bottom: 1px solid #ccc; }
Public domain declaration
Just so there's no confusion: all of the code snippets on this page are provided "AS IS", without warranty of any kind, express or implied.
All of the code snippets on this page are hereby released into the public domain by the me, the copyright holder. This applies worldwide. Or in case this is not legally possible: The copyright holder grants any entity the right to use this work for any purpose, without any conditions, unless such conditions are required by law.
If you'd feel better with a "real" license, you're free to use code snippets on this page under the MIT license as described on the about page.
Any links back to this site are always appreciated, but not required. Enjoy!