strings - template string javascript html
¿Los literales de la plantilla ES6 son más rápidos que la concatenación de cadenas? (5)
TL; DR
La concatenación es más rápida y más consistente con respecto a su velocidad. Pero la diferencia es muy pequeña para 1 o 2 variables (menos de .3 segundos para 100 millones de llamadas).
Editar
Después de la segunda ejecución, parece que la concatenación es principalmente la más rápida de las dos.
Entonces, quería expandir la respuesta de analógico-nico al proporcionar una prueba que fuera más extensa y que también examinara (un poco) la escalabilidad de las dos funciones.
Decidí usar cuatro casos de prueba para cada función, con una variable en el frente, una al final, una en el medio y dos variables en el medio. La configuración básica es la misma. Solo estoy usando 100,000,000 iteraciones de la función y estas iteraciones se ejecutan 100 veces. Utilicé los mismos mecanismos para evitar la optimización, es decir, obtener la suma de las longitudes de las cadenas resultantes y registrarlo. También registré el tiempo necesario (para que adivine cuánto tiempo llevará), pero también lo guardé en una matriz.
Luego, calculé el promedio, el mínimo, el máximo y la desviación estándar para cada método.
Aquí están los resultados:
{
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
}
}
}
los valores en
t
-objects son para plantillas, los valores en
c
-objects son para concatenación.
start
significa que la variable está al principio, a mediados de que está en el medio, final que está al final y doble que hay dos variables.
sum
es la suma de las 100 carreras.
avg
es el promedio de ejecución, lo que significa que es
sum / 100
.
sd
Aquí está la salida fácil, wikipedia (inglés simple)
.
min
y
max
son el valor mínimo y máximo de una ejecución respectivamente.
Resultados
Parece que las plantillas son más rápidas para variables individuales que no se encuentran al final de una cadena, teniendo en cuenta que el promedio es más bajo y el mínimo es más bajo. Si coloca una variable al final de una cadena o tiene varias variables en su cadena, la concatenación es más rápida.
Aunque el mínimo y el promedio de las plantillas es mejor que sus contrapartes de concatenación con respecto a las dos primeras condiciones, la desviación estándar es consistentemente peor. La diferencia parece reducirse con más variables (se necesitan más pruebas).
Dado que la mayoría de las plantillas probablemente no se usarán solo para una variable en una cadena, es seguro decir que apegarse a la concatenación produce un mejor rendimiento. Pero la diferencia es (al menos por ahora) muy marginal. Con 100,000,000 (100 millones) de evaluaciones con dos variables, la diferencia es de solo 273,58 ms, aproximadamente un cuarto de segundo ...
Segunda carrera
La segunda carrera se ve algo diferente. Excepto por el valor máximo, la desviación absoluta promedio y la desviación estándar, cada medición demuestra que la concatenación es más rápida que las plantillas.
Las tres medidas mencionadas tenían valores más bajos (por lo tanto, mejores) para las plantillas cuando la variable estaba al final de la cadena o cuando había dos variables en la cadena.
Aquí están los resultados:
{
"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
}
}
}
¿Alguien ha hecho puntos de referencia? Tengo curiosidad por saber si el código de generación HTML es más rápido con concatenación de cadenas o con literales de plantilla en Node y navegadores modernos.
Por ejemplo:
Concatenación de cadenas
"<body>"+
"<article>"+
"<time datetime=''" + date.toISOString() +"''>"+ date +"</time>"+
"</article>"+
"</body>"
Literal de la plantilla
`<body>
<article>
<time datetime=''${ date.toISOString() }''>${ date }</time>
</article>
</body>`
Creo que el punto de referencia anterior no es útil. El resultado de la interpolación o concatenación no se ha utilizado. Entonces, sí, la concatenación es bastante rápida, porque ninguna cadena de copia de seguridad allí y la cadena de resultados solo tienen enlaces a las cadenas primarias. Pero si prueba la cadena de resultados o la compara con otra, la cadena se serializará en una cadena plana y, sí, llevará algún tiempo. Por lo tanto, la interpolación podría ser más efectiva para el uso de CPU y memoria que la concatenación en casos reales.
Hice una prueba ingenua en node.js v6.0.0 y obtuve casi el mismo rendimiento . Como la prueba es tan ingenua, no creas demasiado los números. Pero parece que el compilador JIT genera código muy optimizado hoy en día. Esto me permitió decidir preferir plantillas a la concatenación para mis aplicaciones de nodo.
Como referencia, este es el código que utilicé:
''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)
Y la salida fue:
strConcat
128888890 - 1904ms
strTemplate
128888890 - 1979ms
Solía
len
para asegurarme absolutamente de que el optimizador no optimiza todo el ciclo.
De todos modos, sigue siendo una prueba muy simple.
Quizás alguien pueda hacer uno más sofisticado.
Para una prueba simple con números aleatorios como cadena, ambos se acercan tanto en Chrome y FF
Pruebas en Chrome 58.0.3029 / Windows 10
Literales de cadena 2,996,883 ± 2.36% más rápido
Operador (+) 3,054,078 ± 2.01% más rápido
Función Concat 2,659,391 ± 2.35% 13% más lenta
Pruebas en Firefox 53.0.2 / Windows 10
Literales de cadena 1,923,835 ± 1.52% más rápido
Operador (+) 1,948,503 ± 1.13% más rápido
Función Concat 1,810,857 ± 1.81% 8% más lenta
Parece que por el momento la concatenación de cadenas es más rápida: 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
Probé que se ejecutó en Chrome 43.0.2334.0 canary (64 bits), que usa V8 4.3.31, con el indicador
#enable-javascript-harmony
habilitado.
Como referencia, la última versión de Node.js (0.12.0 en el momento de la escritura) está utilizando V8 3.28.73: https://raw.githubusercontent.com/joyent/node/master/ChangeLog
Estoy seguro de que todas las optimizaciones de rendimiento posibles que podrían aplicarse aún no se han aplicado, por lo que sería razonable esperar que el rendimiento mejore a medida que ES6 se acerque a la finalización y estas características se migren a la rama estable.
Editar: Gracias por los comentarios @ user1329482, @ icl7126, Nicolai Borisik y FesterCluck. Ahora que han pasado aproximadamente 2 años desde que se hizo esta pregunta, el soporte del navegador ES6 ha aumentado considerablemente y se ha realizado una buena cantidad de optimización del rendimiento. Aquí hay algunas actualizaciones:
En Chrome (a partir de 59.0.3035), los literales de cadena ES6 son más rápidos :
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
En Firefox (a partir de 57.0.0), los literales de cadena ES6 son más rápidos :
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
En Safari (a partir de 11.0.2), depende de:
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
Cuando se usa una cadena de tipografía, los literales de cadena ES6 son más rápidos . Sin embargo, cuando se llama a una función desde el literal, la concatenación de cadenas es más rápida en este ejemplo.
Si realmente quiere profundizar y necesita exprimir cada gota de rendimiento de Safari, sugeriría configurar pruebas que vean si / cómo incorrectamente escribieron variables y referencias múltiples dentro de un rendimiento de efecto literal.