Javascript 为什么字符串连接比数组连接快?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7299010/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:41:26  来源:igfitidea点击:

Why is string concatenation faster than array join?

javascriptperformancestring-concatenation

提问by Sanghyun Lee

Today, I read this threadabout the speed of string concatenation.

今天,我阅读了有关字符串连接速度的主题

Surprisingly, string concatenation was the winner:

令人惊讶的是,字符串连接是赢家:

http://jsben.ch/#/OJ3vo

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 concaton the latest version, but how do they do that? Can we say that it is better to use +when concatenating strings?

我可以猜测浏览器已针对concat最新版本的字符串进行了优化,但它们是如何做到的?能不能说+在连接字符串的时候用比较好?

Update

更新

So, in modern browsers string concatenation is optimized so using +signs is faster than using joinwhen you want to concatenatestrings.

因此,在现代浏览器中,字符串连接得到了优化,因此使用+符号比join在想要连接字符串时使用更快。

But @Arthur pointed outthat joinis faster if you actually want to joinstrings with a separator.

@Arthur 指出join如果您真的想用分隔符连接字符串,速度会更快。

回答by Daan

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

浏览器字符串优化已更改字符串连接图片。

Firefox 是第一个优化字符串连接的浏览器。从 1.0 版开始,数组技术实际上在所有情况下都比使用加号运算符慢。其他浏览器也对字符串连接进行了优化,因此 Safari、Opera、Chrome 和 Internet Explorer 8 也使用 plus 运算符显示出更好的性能。版本 8 之前的 Internet Explorer 没有这样的优化,因此数组技术总是比加号运算符快。

编写高效的 JavaScript:第 7 章 — 更快的网站

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

V8 javascript 引擎(在 Google Chrome 中使用)使用此代码进行字符串连接:

// 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 partsvariable), 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.ccfile for RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)to see the code.

因此,他们在内部通过创建一个 InternalArray(parts变量)来优化它,然后填充它。使用这些部分调用 StringBuilderConcat 函数。它很快是因为 StringBuilderConcat 函数是一些经过高度优化的 C++ 代码。在这里引用太长,但在runtime.cc文件中搜索RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)以查看代码。

回答by evilpie

Firefox is fast because it uses something called Ropes (Ropes: an Alternative to Strings). A rope is basically just a DAG, where every Node is a string.

Firefox 速度很快,因为它使用了一种叫做绳索的东西(绳索:字符串的替代品)。绳索基本上只是一个 DAG,其中每个节点都是一个字符串。

So for example, if you would do a = 'abc'.concat('def'), the newly created object would look like this. Of course this is not exactly how this looks like in memory, because you still need to have a field for the string type, length and maybe other.

因此,例如,如果您这样做a = 'abc'.concat('def'),新创建的对象将如下所示。当然,这与内存中的情况并不完全相同,因为您仍然需要一个用于字符串类型、长度和其他可能的字段。

a = {
 nodeA: 'abc',
 nodeB: 'def'
}

And b = a.concat('123')

b = a.concat('123')

b = {
  nodeA: a, /* {
             nodeA: 'abc',
             nodeB: 'def'
          } */
  nodeB: '123'
}           

So in the simplest case the VM has to do nearly no work. The only problem is that this slows down other operations on the resulting string a little bit. Also this of course reduces memory overhead.

所以在最简单的情况下,VM 几乎不需要做任何工作。唯一的问题是这会稍微减慢对结果字符串的其他操作。这当然也减少了内存开销。

On the other hand ['abc', 'def'].join('')would usually just allocate memory to lay out the new string flat in memory. (Maybe this should be optimized)

另一方面['abc', 'def'].join(''),通常只会分配内存以将新字符串平铺在内存中。(也许这应该优化)

回答by Arthur

I know this is an old thread, but your test is incorrect. You are doing output += myarray[i];while it should be more like output += "" + myarray[i];because you've forgot, that you have to glue items together with something. The concat code should be something like:

我知道这是一个旧线程,但您的测试不正确。你在做的output += myarray[i];时候应该更像是output += "" + myarray[i];因为你忘记了,你必须用某种东西把物品粘在一起。concat 代码应该是这样的:

var output = myarray[0];
for (var i = 1, len = myarray.length; i<len; i++){
    output += "" + myarray[i];
}

That way, you are doing two operations instead of one due to glueing elements together.

这样,由于将元素粘合在一起,您正在执行两个操作而不是一个操作。

Array.join()is faster.

Array.join()是比较快的。

回答by almostA

For large amount of data join is faster, so the question is stated incorrectly.

对于大量数据连接更快,因此问题陈述不正确。

let result = "";
let startTime = new Date().getTime();
for (let i = 0; i < 2000000; i++) {
    result += "x";
}
console.log("concatenation time: " + new Date().getTime() - startTime);

startTime = new Date().getTime();
let array = new Array(2000000);
for (let i = 0; i < 2000000; i++) {
    array[i] = "x";
}
result = array.join("");
console.log("join time: " + new Date().getTime() - startTime);

Tested on Chrome 72.0.3626.119, Firefox 65.0.1, Edge 42.17134.1.0. Note that it is faster even with the array creation included!

在 Chrome 72.0.3626.119、Firefox 65.0.1、Edge 42.17134.1.0 上测试。请注意,即使包含数组创建,它也更快!

回答by Jeremy Moritz

The benchmarks there are trivial. Concatenating the same three items repeatedly will be inlined, the results will proven deterministic and memoized, the garbage handler will be just throwing away array objects (which will be next to nothing in size) and probably just pushed and popped off the stack due to no external references and because the strings never change. I would be more impressed if the test was a large number of randomly generated strings. As in a gig or two's worth of strings.

那里的基准是微不足道的。重复连接相同的三个项目将被内联,结果将被证明是确定性和记忆的,垃圾处理程序将只是扔掉数组对象(几乎没有大小)并且可能只是因为没有外部引用,因为字符串永远不会改变。如果测试是大量随机生成的字符串,我会印象更深刻。就像在一两场演出中一样。

Array.join FTW!

Array.join FTW!

回答by xanatos

I would say that with strings it's easier to preallocate a bigger buffer. Each element is only 2 bytes (if UNICODE), so even if you are conservative, you can preallocate a pretty big buffer for the string. With arrayseach element is more "complex", because each element is an Object, so a conservative implementation will preallocate space for less elements.

我会说使用字符串更容易预分配更大的缓冲区。每个元素只有 2 个字节(如果是 UNICODE),因此即使您很保守,也可以为字符串预先分配一个相当大的缓冲区。与arrays每个元素是更“复杂”的,因为每个元件是一个Object,所以保守实施将预分配的空间更少的元件。

If you try to add a for(j=0;j<1000;j++)before each foryou'll see that (under chrome) the difference in speed becomes smaller. In the end it was still 1.5x for the string concatenation, but smaller than the 2.6 that was before.

如果您尝试for(j=0;j<1000;j++)在每个之前添加一个,for您会看到(在 chrome 下)速度差异变小。最后它仍然是字符串连接的 1.5 倍,但比之前的 2.6 小。

AND having to copy the elements, an Unicode character is probably smaller than a reference to a JS Object.

并且必须复制元素,Unicode 字符可能小于对 JS 对象的引用。

Be aware that there is the possibility that many implementations of JS engines have an optimization for single-type arrays that would make all I have written useless :-)

请注意,JS 引擎的许多实现都有可能对单类型数组进行优化,这会使我写的所有内容都无用:-)

回答by srgstm

This testshows the penalty of actually using a string made with assignment concatenation vs made with array.join method. While the overall speed of assignment is still twice as fast in Chrome v31 but it is no longer as huge as when not using the resultant string.

此测试显示了实际使用通过赋值连接制作的字符串与使用 array.join 方法制作的字符串的惩罚。虽然在 Chrome v31 中分配的整体速度仍然是两倍,但它不再像不使用结果字符串时那么快。

回答by Vanuan

This clearly depends on the javascript engine implementation. Even for different versions of one engine you can get significally different results. You should do your own benchmark to verify this.

这显然取决于 javascript 引擎实现。即使对于一个引擎的不同版本,您也可以获得截然不同的结果。您应该做自己的基准测试来验证这一点。

I would say that String.concathas better performance in the recent versions of V8. But for Firefox and Opera, Array.joinis a winner.

我会说它String.concat在最近版本的 V8中具有更好的性能。但对于 Firefox 和 Opera 来说,Array.join是赢家。

回答by Marcelo Cantos

My guess is that, while every version is wearing the cost of many concatenations, the join versions are building arrays in addition to that.

我的猜测是,虽然每个版本都承受了许多连接的成本,但除此之外,连接版本还在构建数组。