Либо литералы ES6 быстрее, чем конкатенация строк?
Кто-нибудь сделал тесты? Мне любопытно, если код генерации HTML быстрее с конкатенацией строк или с литералами шаблонов в Node и современных браузерах.
Например:
Конкатенация строк
"<body>"+
"<article>"+
"<time datetime='" + date.toISOString() +"'>"+ date +"</time>"+
"</article>"+
"</body>"
Литературный шаблон
`<body>
<article>
<time datetime='${ date.toISOString() }'>${ date }</time>
</article>
</body>`
Ответы
Ответ 1
Кажется, на данный момент конкатенация строк происходит быстрее: 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 (64-разрядная версия), который использует 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 значительно возросла, и была достигнута значительная оптимизация производительности. Вот некоторые обновления:
В 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
При использовании строки Typecast строковые литералы ES6 работают быстрее. Однако при вызове функции из литерала конкатенация строк в этом примере выполняется быстрее.
Если вы действительно хотите углубиться и вам нужно выжать каждую каплю производительности из Safari, я бы предложил создать тесты, которые проверяют, правильно ли введены переменные и множественные ссылки в пределах литеральной производительности.
Ответ 2
Я сделал наивный тест на node.js v6.0.0 и получил почти ту же производительность. Поскольку тест настолько наивен, не верьте слишком большим числам. Но, похоже, компилятор JIT генерирует очень оптимизированный код в наши дни. Это позволило мне выбрать предпочтительные шаблоны для конкатенации для моих приложений node.
Для справки это код, который я использовал:
'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
, чтобы убедиться, что оптимизатор не оптимизирует весь цикл. Во всяком случае, это еще очень простой тест. Возможно, кто-то может сделать более сложный.
Ответ 3
Для простого теста со случайными числами как строкой, оба приближаются так близко в 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% медленнее
Проверить здесь на jsperf
Ответ 4
TL; DR
Конкатенация быстрее и более последовательна в отношении ее скорости.
Но разница очень мало для 1 или 2 переменных (ниже 0,3 секунды для 100 миллионов вызовов).
Изменить
После второго запуска кажется, что конкатенация в основном быстрее из двух.
Итак, я хотел развернуть аналог-nico ответ, предоставив тест, который был более обширным, а также немного посмотрел на масштабируемость двух функций.
Код на pastebin
Я решил использовать четыре тестовых примера для каждой функции, имея переменную спереди, одну в конце, одну в середине и две переменные в середине. Базовая установка такая же. Я просто использую 100 000 000 итераций функции, и эти итерации выполняются 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
-объектах предназначены для шаблонов, значения в c
-объектах предназначены для конкатенации. start
означает, что переменная находится в начале, в середине, когда она находится в середине, заканчивается, что она находится в конце и в два раза, что есть две переменные. sum
- сумма всех 100 прогонов. avg
- средний пробег, что означает sum / 100
. sd
Вот простой выход, wikipedia (простой английский). min
и max
являются минимальным и максимальным значением пробега соответственно.
Результаты
Кажется, что шаблоны быстрее для одиночных переменных, которые не расположены в конце строки, учитывая, что среднее значение меньше, а минимальное - ниже. Если вы поместите переменную в конец строки или имеете несколько переменных в своей строке, конкатенация выполняется быстрее.
Несмотря на то, что как минимум, так и среднее число шаблонов лучше, чем их конкатенационные аналоги в отношении первых двух условий, стандартное отклонение последовательно хуже. Разница, похоже, сокращается с большим количеством переменных (требуется больше тестов).
Так как большинство шаблонов, вероятно, не будут использоваться только для одной переменной в строке, можно сказать, что прилипание к конкатенации дает лучшую производительность.
Но разница (по крайней мере на данный момент) очень незначительна. При 100 000 000 (100 миллионов) оценок с двумя переменными разница составляет всего 273,58 мс, около четверти секунды...
Второй запуск
Второй прогон выглядит несколько иначе. За исключением максимального значения, среднего абсолютного отклонения и стандартного отклонения, каждое измерение подтвердило, что конкатенация выполняется быстрее, чем шаблоны.
Три упомянутых измерения имели более низкие (тем самым лучшие) значения для шаблонов, когда переменная находилась в конце строки или когда в строке были две переменные.
Вот результаты:
{
"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
}
}
}
Код здесь
Ответ 5
Я думаю, что тест выше не полезен. Результат интерполяции или конкатенации не используется. Так что да, конкатенация довольно быстрая, потому что ни одна строка не копируется, а строка результата имеет только ссылки на родительские строки. Но если вы попробуете строку результата или сравните с другой, строка будет сериализована в плоскую строку и, да, это займет некоторое время. Таким образом, интерполяция может быть более эффективной для использования процессора и памяти, чем конкатенация в реальных случаях.