High-performance String Concatenation in JavaScript

Contributing Editor

Concatenation, or joining strings, is an important facility within any programming language. It’s especially vital within web applications, since strings are regularly used to generate HTML output. Several languages offer fast string-handling classes such as StringBuilder in .NET and StringBuffer/StringBuilder in Java.

There are a number of ways to concatenate strings in JavaScript:


str = "a" + "b";
str += "c";
str = str.concat("d", "e");

You can also join an array of strings:


str = ["a", "b", "c", "d", "e"].join("");

If you’re only joining a few strings, you should use whichever method is most practical. Performance gains or losses will be negligible in all browsers.

Concatenating Many Strings

Consider the following functionally identical examples. The first uses the string concatenation operator:


// standard string append
var str = "";
for (var i = 30000; i > 0; i--) {
	str += "String concatenation. ";
}

The second uses an array join:


// array join
var str = "", sArr = [];
for (var i = 30000; i > 0; i--) {
	sArr[i] = "String concatenation. ";
}
str = sArr.join("");

Which will execute the fastest?

Some developers will assume the concatenation operator is faster because it uses less code and doesn’t require an array that doubles memory requirements. For others, conventional wisdom dictates that array joins are faster—it’s more memory efficient within the JavaScript interpreter.

The truth is rather more complex. In all the most recent browsers, either method is fast and will complete within 80ms on a mid-range PC. Here are the results from my own completely unscientific benchmark tests:

  • Chrome 6.0: standard string appends are usually quicker than array joins, but both complete in less than 10ms.
  • Opera 10.6: again, standard appends are quicker, but the difference is marginal—often 15ms compared to 17ms for an array join.
  • Firefox 3.6: the browser normally takes around 30ms for either method. Array joins usually have the edge, but only by a few milliseconds.
  • IE 8.0: a standard append requires 30ms, whereas an array join is more than double—typically 70ms.
  • Safari 5.0.1: bizarrely, a standard append takes no more than 5ms but an array join is more than ten times slower at 55ms.

The latest JavaScript engines are optimized for string concatenation operators. Array joins remain fast, but are without a performance gain.

The flIEs in the ointment

IE7 is the world’s third-most-used browser with a 14% market share. IE6 accounts for another 8%. There’s no need to read further if you’ve dropped support for these aging applications.

Still here? This is the shocker: IE7 and below use a concatenation handler that repeatedly copies strings and causes an exponential increase in time and memory usage. The code using the concatenation operator takes around 2.5 minutes (150,000ms) to execute, and the browser remains unresponsive throughout. By comparison, the array join completes in under 200ms—it’s more than 800 times faster.

If you’re supporting IE7, array joins remain the best method for concatenating a large number of strings.

What about PHP? Tune in soon for the test results…

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • ahallicks

    2.5 minutes actually just blew my mind. That is ridiculous! Thanks for the info :-)

    • iFadey

      You are right. 2.5 min is too much :P

  • http://www.brothercake.com/ brothercake

    Nice tip – IE is certainly optimized in some strange ways.
    There’s also a neat combination of join() and split() you can use to reduce repetitive data stored in arrays. For example – you have an array of file paths, but each path is substantially the same; so store the path, prefix, and name separately, and join them together at the last minute:
    var path = ‘/images/flags/worldcup/qualifiers/’,
    suffix = ‘.png’,
    flags = ['brazil','cameroon','japan','spain'];

    flags = (path + flags.join(suffix + ‘,’ + path) + suffix).split(‘,’);

  • Oliver

    In your timings are you attempting to use the strings?

    eg.
    for (var i =0; i < …; i++) {
    var s = makeString(); // or whatever
    s[s.length - 1];
    }

    ?

    • http://www.optimalworks.net/ Craig Buckler

      No — the timings are based on the code as written above. A date() object was created at either end of the code and the difference in ms was calculated.

  • http://www.namics.com tjunghans

    Hi Craig
    When I run the following block of code in Firebug’s Console (Firefox 3.6.9, Firebug 1.5.4) I get the best result for “join”. To be exact:
    append: 105.222ms
    concat: 136.778ms
    join: 93.18ms
    Any ideas why this may be? Do you get the same or similar results?
    Cheers
    TJ
    console.clear();
    var string = ”;
    var i = 100000, j = 0;
    console.profile(‘append’);
    (function () {
    j = i;
    while(j > 0) {
    string += ‘foo’;
    –j;
    }
    }());
    console.profileEnd(‘append’);
    console.info(string.length);
    string = ”;
    console.profile(‘concat’);
    (function () {
    j = i;
    while(j > 0) {
    string = string.concat(‘foo’);
    –j;
    }
    }());
    console.profileEnd(‘concat’);
    console.info(string.length);
    string = [];
    console.profile(‘join’);
    (function () {
    j = i;
    while(j > 0) {
    string.push(‘foo’);
    –j;
    }
    }());
    string = string.join(”);
    console.profileEnd(‘join’);
    console.info(string.length);

    • http://www.optimalworks.net/ Craig Buckler

      Hi tjunghans,

      As mentioned above, array joins in Firefox appear to be marginally faster than concatenation operators. Your code shows that it’s 12ms quicker for a loop of 100,000 strings. My tests showed a difference of 2 or 3ms on 30,000 strings.

      Array joins are normally faster in older interpreters because the bulk of the work is completed in one fast operation rather than many small ones. But it makes very little difference in newer browsers — they are probably compiling code or using more efficient memory handling techniques.

  • http://www.namics.com tjunghans

    Ah yes, of course. I must have overlooked that. Which method would you go for, if you were developing a web app with crossbrowser support including IE7?
    Go with the array join or use one of the methods above depending on the browser?
    -TJ

    • http://www.optimalworks.net/ Craig Buckler

      It really depends whether you’ve got any large string operations. The examples above are useful for benchmarking, but you’re unlikely to concatenate 30,000 strings in a real application.

      I’d suggest using whatever is practical. Test in IE7 early — if concatenation causes serious issues, you re-factor your code accordingly.

  • Vic

    There has been a jsPerf test case for exactly this, since August: http://jsperf.com/concatenation-vs-array-join Might be useful to reference that since it automatically gathers the results per browser.

  • Sam Foster

    There’s a couple performance tests along these lines at jsperf.com, e.g.
    http://jsperf.com/multiline-string/2 (I just forked in response to this article).

    also:
    http://jsperf.com/string-concatenation/3
    http://jsperf.com/string-concatenation-test/2
    ..and others of varying utility.

    This 2 articles might be of interest, on Sitepen’s blog, which provide some in-depth analysis on string building techniques in the browsers of the day:
    http://www.sitepen.com/blog/2008/05/09/string-performance-an-analysis/
    http://www.sitepen.com/blog/2008/06/09/string-performance-getting-good-performance-from-internet-explorer/

  • extraneu

    What about preallocating the array?

  • JamesFarrell

    I attended a talk by Florian Loitsch, who works on the Google Chrome team and he warned against making assumptions like this because the browser’s Javascript engines may be optimised in unexpected way and this is a good example of that.

    • http://www.brothercake.com/ brothercake

      because the browser’s Javascript engines may be optimised in unexpected ways

      Spoken like a man working on closed-source technologies!

  • JamesFarrell

    Who me or Florian?