Why is string concatenation faster than array join?

Sanghyun Lee picture Sanghyun Lee · Sep 4, 2011 · Viewed 93.5k times · Source

Today, I read this thread about the speed of string concatenation.

Surprisingly, string concatenation was the winner:

http://jsben.ch/#/OJ3vo

The result was opposite of what I thought. Besides, there are many articles about this which explain oppositely like this.

I can guess that browsers are optimized to string concat on the latest version, but how do they do that? Can we say that it is better to use + when concatenating strings?


Update

So, in modern browsers string concatenation is optimized so using + signs is faster than using join when you want to concatenate strings.

But @Arthur pointed out that join is faster if you actually want to join strings with a separator.


Update - 2020
Chrome: Array join is almost 2 times faster is String concat + See: https://stackoverflow.com/a/54970240/984471

As a note:

  • Array join is better if you have large strings
  • If we need generate several small strings in final output, it is better to go with string concat +, as otherwise going with Array will need several Array to String conversions at the end which is performance overload.

Answer

Daan picture Daan · Sep 4, 2011

Browser string optimizations have changed the string concatenation picture.

Firefox was the first browser to optimize string concatenation. Beginning with version 1.0, the array technique is actually slower than using the plus operator in all cases. Other browsers have also optimized string concatenation, so Safari, Opera, Chrome, and Internet Explorer 8 also show better performance using the plus operator. Internet Explorer prior to version 8 didn’t have such an optimization, and so the array technique is always faster than the plus operator.

Writing Efficient JavaScript: Chapter 7 – Even Faster Websites

The V8 javascript engine (used in Google Chrome) uses this code to do string concatenation:

// ECMA-262, section 15.5.4.6
function StringConcat() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
  }
  var len = %_ArgumentsLength();
  var this_as_string = TO_STRING_INLINE(this);
  if (len === 1) {
    return this_as_string + %_Arguments(0);
  }
  var parts = new InternalArray(len + 1);
  parts[0] = this_as_string;
  for (var i = 0; i < len; i++) {
    var part = %_Arguments(i);
    parts[i + 1] = TO_STRING_INLINE(part);
  }
  return %StringBuilderConcat(parts, len + 1, "");
}

So, internally they optimize it by creating an InternalArray (the parts variable), which is then filled. The StringBuilderConcat function is called with these parts. It's fast because the StringBuilderConcat function is some heavily optimized C++ code. It's too long to quote here, but search in the runtime.cc file for RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) to see the code.