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 / 100
。 sd
这里是简单的出路,维基百科(简体中文) 。 min
和max
分别是运行的最小值和最大值。
结果
对于不在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 } } }
代码在这里