誰もベンチマークをしましたか? HTML生成コードが、文字列の連結またはNodeおよび最新のブラウザーのテンプレートリテラルを使用した場合に高速になるかどうかに興味があります。
例えば:
文字列連結
"<body>"+
"<article>"+
"<time datetime='" + date.toISOString() +"'>"+ date +"</time>"+
"</article>"+
"</body>"
テンプレートリテラル
`<body>
<article>
<time datetime='${ date.toISOString() }'>${ date }</time>
</article>
</body>`
今のところ、文字列の連結が高速になっているようです: 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
テストしたのは、Chrome 43.0.2334.0 canary(64-bit)、V8 4.3.31を使用し、#enable-javascript-harmony
フラグが有効になっています。
参考として、Node.jsの最新バージョン(執筆時点では0.12.0)はV8 3.28.73を使用しています: https://raw.githubusercontent.com/joyent/node/master/ChangeLog =
適用可能なパフォーマンスの最適化はまだすべて適用されていないので、ES6がファイナライズに近づき、これらの機能が安定ブランチに移行されるにつれてパフォーマンスが向上すると期待するのは合理的です。
編集:コメント@ user1329482、@ icl7126、ニコライボリシク、およびFesterCluckに感謝します。この質問が出されてから約2年が過ぎた今、ES6ブラウザーのサポートが大幅に増加し、かなりのパフォーマンスの最適化が行われました。更新内容は次のとおりです。
In Chrome(59.0.3035現在)、ES6文字列リテラルは高速です:
ES6 with variable 48,161,401 ±1.07% fastest
String concatenation with variable 27,046,298 ±0.48% 44% slower
ES6 with function 820,441 ±1.10% 98% slower
String concatenation with function 807,088 ±1.08% 98% slower
Firefox(57.0.0以降)では、ES6文字列リテラルは高速です:
ES6 with variable 1,924,610,984 ±0.50% fastest
String concatenation with variable 1,876,993,458 ±0.79% 3% slower
ES6 with function 539,762 ±5.04% 100% slower
String concatenation with function 546,030 ±5.88% 100% slower
Safari(11.0.2以降)では、以下に依存します。
ES6 with variable 1,382,752,744 ±0.71% fastest
String concatenation with variable 1,355,512,037 ±0.70% 2% slower
ES6 with function 876,516 ±1.01% 100% slower
String concatenation with function 883,370 ±0.79% 100% slower
型キャスト文字列を使用する場合、ES6文字列リテラルは高速です。ただし、リテラルから関数を呼び出す場合、この例ではstring concatenationの方が高速です。
本当に深くしたいので、Safariからパフォーマンスの低下をすべて絞り出す必要がある場合は、リテラルエフェクトパフォーマンス内の変数と複数の参照のタイプが間違っているかどうかを確認するテストを設定することをお勧めします。
node.js v6.0.で素朴なテストを行い、ほぼ同じパフォーマンスを得ました。テストは非常に単純なので、数字をあまり信じないでください。しかし、最近ではJITコンパイラが非常に最適化されたコードを生成しているようです。これにより、ノードアプリの連結よりもテンプレートを優先することにしました。
参考のために、これは私が使用したコードです:
'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
を使用して、オプティマイザーがループ全体を最適化しないようにします。とにかく、それはまだ非常に簡単なテストです。誰かがもっと洗練されたものを作れるかもしれません。
文字列として乱数を使用した簡単なテストの場合、両方ともChrome&FF
Chrome 58.0.3029/Windows 10でのテスト
文字列リテラル2,996,883±2.36%最速
演算子(+)3,054,078最速±2.01%
連結機能2,659,391±2.35%13%遅い
Firefox 53.0.2/Windows 10でのテスト
文字列リテラル1,923,835±1.52%最速
オペレーター(+)1,948,503最速±1.13%
連結機能1,810,857±1.81%8%遅い
連結は、速度に関してより速く、より一貫しています。ただし、変数が1つまたは2つの場合、違いはごくわずかです(1億回の呼び出しで0.3秒未満)。
2回目の実行後、連結は主に2つの高速のようです。
そこで、私は analog-nicoの答え を拡張したいと考えました。テストはより広範で、2つの機能のスケーラビリティを(少し)調べました。
各関数に4つのテストケースを使用することにしました。前部に変数があり、最後に1つ、中央に1つ、中央に2つの変数があります。基本的なセットアップは同じです。関数の1億回の反復を使用しているだけで、これらの反復は100回実行されます。同じメカニズムを使用して最適化を防止しました。つまり、結果の文字列の長さの合計を取得してログに記録しました。また、必要な時間も記録しました(所要時間を推測するため)、配列に保存しました。
その後、各メソッドの平均、最小、最大、標準偏差を計算しました。
結果は次のとおりです。
{
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
は、変数が先頭にあること、中間にあること、中間にあること、最後にあること、2つの変数があることを意味します。 sum
は、100回すべての実行の合計です。 avg
は平均実行です。つまり、sum / 100
。 sd
ここに簡単な方法があります、ウィキペディア(シンプルな英語) 。 min
とmax
は、それぞれ実行の最小値と最大値です。
平均がより低く、最小がより低いことを考慮すると、文字列の末尾にない単一の変数の場合、テンプレートはより高速であるようです。文字列の末尾に変数を配置するか、文字列に複数の変数を含めると、連結が高速になります。
最初の2つの条件に関して、テンプレートの最小値と平均値は、対応する連結値よりも優れていますが、標準偏差は一貫して悪化しています。違いは、変数が増えると縮小するようです(さらにテストが必要です)。
ほとんどのテンプレートはおそらく文字列内の1つの変数のみに使用されるわけではないため、連結に固執するとパフォーマンスが向上するということは言うまでもありません。しかし、違いは(少なくとも今のところ)非常にわずかです。 2つの変数による1億回(1億回)の評価では、差はわずか273,58ミリ秒で、約4分の1秒です...
2回目の実行は多少異なります。最大値、平均絶対偏差、標準偏差を除き、すべての測定で、連結がテンプレートよりも高速であることが証明されました。
変数が文字列の末尾にある場合、または文字列に2つの変数がある場合、言及された3つの測定値は、テンプレートの値が低い(したがって優れている)。
結果は次のとおりです。
{
"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
}
}
}
上記のベンチマークは役に立たないと思います。補間または連結の結果は使用されていません。そのため、連結は非常に高速です。なぜなら、そこに対処する文字列と結果の文字列には親文字列へのリンクしかないためです。ただし、結果の文字列を試してみるか、別の文字列と比較すると、文字列はプレーン文字列にシリアル化され、はい、時間がかかります。したがって、実際の場合の連結よりも、CPUとメモリの使用に対して補間の方が効果的です。