ES6模板文字比string连接更快吗?

有没有人做基准? 我很好奇,如果HTML生成代码更快与string连接或与节点和现代浏览器中的模板文字。

例如:

string连接

"<body>"+ "<article>"+ "<time datetime='" + date.toISOString() +"'>"+ date +"</time>"+ "</article>"+ "</body>" 

模板文字

 `<body> <article> <time datetime='${ date.toISOString() }'>${ date }</time> </article> </body>` 

看来现在string连接速度更快 : http : //jsperf.com/es6-string-literals-vs-string-concatenation

 ES6 with variable 19,992,512 ±5.21% 78% slower String concatenation with variable 89,791,408 ±2.15% fastest ES6 with function 461,358 ±3.12% 99% slower String concatenation with function 503,255 ±1.77% 99% slower 

我testing的是在使用V8 4.3.31的Chrome 43.0.2334.0 canary(64位)上运行的, #enable-javascript-harmony#enable-javascript-harmony标志。

作为参考,Node.js上的最新版本(撰写本文时为0.12.0)使用V8 3.28.73: https ://raw.githubusercontent.com/joyent/node/master/ChangeLog

我确信所有可能的性能优化都可以应用到现在还没有被应用,所以当ES6接近完成并且这些特性被迁移到稳定的分支时,期望性能会变得更好是合理的。

我在node.js v6.0.0上做了一个天真的testing, 性能几乎相同 。 既然考试太天真了,不要太相信数字。 但是现在似乎JIT编译器会生成非常优化的代码。 这让我决定select模板而不是连接节点应用程序。

作为参考,这是我使用的代码:

 'use strict' function strConcat(i) { return 'abc' + i + 'def' } function strTemplate(i) { return `abc${i}def` } function run(strategy) { let before = new Date().getTime() let len = 0 for ( let i = 0; i < 10000000; i+=1 ) { len += strategy(i).length } console.log(len + ' - ' + ((new Date().getTime()) - before) + 'ms') } console.log('strConcat') run(strConcat) console.log('strTemplate') run(strTemplate) 

产出是:

 strConcat 128888890 - 1904ms strTemplate 128888890 - 1979ms 

我用len来绝对确保优化器不会优化整个循环。 无论如何,这仍然是一个非常简单的testing。 也许有人可以做一个更复杂的。

对于随机数字作为string的简单testing,两者在Chrome和FF中都非常接近

在Chrome 58.0.3029 / Windows 10中testing

string文字最快2,996,883±2.36%

运营商(+)最快3,054,078±2.01%

Concatfunction2,659,391±2.35%慢13%

在Firefox 53.0.2 / Windows 10中testing

string文字1,923,835±1.52%最快

操作员(+)1,948,503±1.13%最快

Concatfunction1,810,857±1.81%慢8%

在这里testingjsperf

TL; DR

连接速度更快,更一致。 但是对于1或2个variables(1亿次呼叫的.3秒以下)差别非常小。

编辑

在第二次运行后,似乎连接大部分是两者中较快的。


所以,我想通过提供一个更广泛的testing来扩展analog-nico的答案 ,并且还对这两个函数的可扩展性进行了一些研究。

在pastebin上的代码

我决定对每个函数使用四个testing用例,前面有一个variables,最后一个variables,中间有一个variables,中间有两个variables。 基本的设置是一样的。 我只使用了100,000,000次函数迭代,这些迭代运行了100次。 我使用了相同的机制来防止优化,即获得结果string的长度和logging它的总和。 我还logging了所需的时间(对于我来猜测需要多长时间),还将其保存到数组中。

之后,我计算了每种方法的平均值,最小值,最大值和标准偏差。

结果如下:

 { sum: { t: { start: 2072751, mid: 2338476, end: 2083695, double: 2950287 }, c: { start: 2086059, mid: 2345551, end: 2074732, double: 2922929 } }, avg: { t: { start: 20727.51, mid: 23384.76, end: 20836.95, double: 29502.87 }, c: { start: 20860.59, mid: 23455.51, end: 20747.32, double: 29229.29 } }, sd: { t: { start: 335.6251329981114, mid: 282.9490809315344, end: 286.2220947096852, double: 216.40844045461824 }, c: { start: 255.4803356424913, mid: 221.48744862858484, end: 238.98242111084238, double: 209.9309074433776 } }, min: { t: { start: 20490, mid: 23216, end: 20588, double: 29271 }, c: { start: 20660, mid: 23258, end: 20534, double: 28985 } }, max: { t: { start: 23279, mid: 25616, end: 22887, double: 30843 }, c: { start: 22603, mid: 25062, end: 22403, double: 30536 } } } 

t objects中的值是模板的值, c -objects中的值是连接的。 start意味着variables在开始,中间在中间,结束在结尾,双重在两个variables。 sum是所有100次运行的总和。 avg是平均值,意思是sum / 100sd 这里是简单的出路,维基百科(简体中文) 。 minmax分别是运行的最小值和最大值。

结果

对于不在string末尾的单个variables,模板似乎比较快,考虑到平均值较低,最小值较低。 如果你把一个variables放在一个string的末尾或者在你的string中有多个variables,连接速度会更快。

虽然模板的最小值和平均值都优于前两个条件的连接对应值,但标准差一直较差。 差异似乎缩小更多的variables(需要更多的testing)。

由于大多数模板不可能仅用于string中的一个variables,所以说坚持拼接会产生更好的性能。 但差别是(至less现在)非常小。 以两个variables进行的100,000,000(1亿次)评估中,差异仅为273,58 ms,大约四分之一秒…


第二次运行

第二轮看起来有些不同。 除了最大值,平均绝对偏差和标准偏差之外,每个测量都certificate了级联比模板快。

当variables位于string末尾或string中有两个variables时,上述三个测量结果的模板值都较低(因此更好)。

结果如下:

 { "sum": { "t": { "start": 1785103, "mid": 1826679, "end": 1719594, "double": 2110823, "many": 4153368 }, "c": { "start": 1720260, "mid": 1799579, "end": 1716883, "double": 2097473, "many": 3836265 } }, "avg": { "t": { "start": 17851.03, "mid": 18266.79, "end": 17195.94, "double": 21108.23, "many": 41533.68 }, "c": { "start": 17202.6, "mid": 17995.79, "end": 17168.83, "double": 20974.73, "many": 38362.65 } }, "sd": { "t": { "start": 858.7857061572462, "mid": 886.0941856823124, "end": 786.5366719994689, "double": 905.5376950188214, "many": 1744.9005638144542 }, "c": { "start": 599.0468429096342, "mid": 719.1084521127534, "end": 935.9367719563112, "double": 991.5642274204934, "many": 1465.1116774840066 } }, "aad": { "t": { "start": 579.1207999999996, "mid": 576.5628000000003, "end": 526.8268, "double": 586.9651999999998, "many": 1135.9432000000002 }, "c": { "start": 467.96399999999966, "mid": 443.09220000000016, "end": 551.1318000000008, "double": 610.2321999999999, "many": 1020.1310000000003 } }, "min": { "t": { "start": 16932, "mid": 17238, "end": 16387, "double": 20016, "many": 39327 }, "c": { "start": 16477, "mid": 17137, "end": 16226, "double": 19863, "many": 36424 } }, "max": { "t": { "start": 23310, "mid": 24102, "end": 21258, "double": 26883, "many": 49103 }, "c": { "start": 19328, "mid": 23203, "end": 22859, "double": 26875, "many": 44352 } }, "median": { "t": { "start": 17571, "mid": 18062, "end": 16974, "double": 20874, "many": 41171.5 }, "c": { "start": 16893.5, "mid": 18213, "end": 17016.5, "double": 20771, "many": 38849 } } } 

代码在这里