w3schools tag tab style page for color javascript optimization google-closure-compiler

javascript - tag - ¿El compilador de cierre de Google disminuye el rendimiento?



title of page html (3)

Estoy escribiendo una extensión de Google Chrome. Como los archivos de JavaScript se cargan desde el disco, su tamaño apenas importa.

De todos modos, he estado usando Google Closure Compiler porque aparentemente puede hacer optimizaciones de rendimiento y reducir el tamaño del código.

Pero noté esto en la parte superior de mi salida de Closure Compiler:

var i = true, m = null, r = false;

El objetivo de esto es, obviamente, reducir el tamaño del archivo (todos los usos posteriores de true / null / false largo del script pueden reemplazarse por caracteres individuales).

¿Pero seguramente hay un pequeño golpe de rendimiento con eso? Debe ser más rápido simplemente leer una palabra clave true literal que buscar una variable por nombre y encontrar que su valor es true ...?

¿Vale la pena preocuparse por este golpe de rendimiento? ¿Y hay algo más que Google Closure Compiler pueda hacer que realmente ralentice la ejecución?


La respuesta es tal vez .

Veamos lo que dice el equipo de cierre al respecto.

De las preguntas frecuentes :

¿El compilador hace concesiones entre la velocidad de ejecución de mi aplicación y el tamaño del código de descarga?

Sí. Cualquier compilador optimizador hace concesiones. Algunas optimizaciones de tamaño introducen gastos generales de pequeña velocidad. Sin embargo, los desarrolladores de Closure Compiler han tenido cuidado de no introducir tiempo de ejecución adicional significativo. Algunas de las optimizaciones del compilador incluso disminuyen el tiempo de ejecución (vea la siguiente pregunta).

¿El compilador optimiza la velocidad?

En la mayoría de los casos, el código más pequeño es el más rápido, ya que el tiempo de descarga suele ser el factor de velocidad más importante en las aplicaciones web. Las optimizaciones que reducen las redundancias también aceleran el tiempo de ejecución del código.

Desafío rotundamente la primera suposición que han hecho aquí. El tamaño de los nombres de las vars utilizadas no afecta directamente la forma en que los distintos motores de JavaScript tratan el código; de hecho, a los motores JS no les importa si consideras que tus variables son supercalifragilisticexpialidocious o x (pero yo, como programador, sí). El tiempo de descarga es la parte más importante si le preocupa la entrega: un script de ejecución lenta puede ser causado por millones de cosas que sospecho que la herramienta simplemente no puede explicar.

Para comprender realmente por qué tu pregunta es tal vez, lo primero que debes preguntar es "¿Qué hace que JavaScript sea rápido o lento?"

Luego, por supuesto, nos encontramos con la pregunta: "¿De qué motor de JavaScript estamos hablando?"

Tenemos:

  • Carakan (Ópera)
  • Chakra (IE9 +)
  • SpiderMonkey (Mozilla / FireFox)
  • SquirrelFish (webkit de Apple)
  • V8 (Chrome)
  • Futhark (Ópera)
  • JScript (todas las versiones de IE antes de 9)
  • JavaScriptCore (Konqueror, Safari)
  • Me he saltado algunos .

¿Alguien aquí realmente cree que todos trabajan igual? Especialmente JScript y V8? ¡Diablos no!

Entonces, una vez más, cuando el cierre de Google compila el código, ¿para qué motor lo está construyendo? ¿Te sientes con suerte?

Está bien, porque nunca cubriremos todas estas bases, tratemos de buscar de forma más general aquí, en el código "antiguo" frente a "nuevo".

Aquí hay un breve resumen de esta parte específica de una de las mejores presentaciones sobre JS Engines que he visto .

Motores JS más antiguos

  • El código se interpreta y compila directamente al código de bytes.
  • Sin optimización: obtienes lo que obtienes
  • El código es difícil de ejecutar rápido debido al lenguaje vagamente escrito

Nuevos motores JS

  • Introduzca compiladores Just-In-Time (JIT) para una ejecución rápida
  • Introduzca compiladores JIT de optimización de tipo para un código realmente rápido (piense cerca de las velocidades de código C)

La diferencia clave aquí es que los nuevos motores introducen compiladores JIT.

En esencia, JIT optimizará la ejecución de su código de modo que pueda ejecutarse más rápido, pero si sucede algo que no le gusta, se da la vuelta y lo vuelve lento nuevamente.

Puedes hacer esas cosas teniendo dos funciones como esta:

var FunctionForIntegersOnly = function(int1, int2){ return int1 + int2; } var FunctionForStringsOnly = function(str1, str2){ return str1 + str2; } alert(FunctionForIntegersOnly(1, 2) + FunctionForStringsOnly("a", "b"));

Ejecutar eso a través del cierre de Google en realidad simplifica todo el código a:

alert("3ab");

Y por cada métrica en el libro que es mucho más rápido. Lo que realmente sucedió aquí es que simplificó mi ejemplo realmente simple, porque hace un poco de ejecución parcial. Sin embargo, aquí es donde debes tener cuidado.

Digamos que tenemos un combinador y en nuestro código , el compilador lo convierte en algo como esto:

(function(a) { return function(b) { return a(a)(b) } })(function(a) { return function(b) { if(b > 0) { return console.log(b), a(a)(b - 1) } } })(5);

No es realmente más rápido, simplemente minimiza el código.

Normalmente, JIT verá que, en la práctica, su código solo toma dos entradas de cadena para esa función y devuelve una cadena (o un entero para la primera función), y esto lo coloca en el JIT específico del tipo, lo que lo hace realmente rápido. Ahora, si el cierre de google hace algo extraño como transformar ambas funciones que tienen firmas casi idénticas en una función (para el código que no es trivial), puede perder la velocidad de JIT si el compilador hace algo que no le gusta a JIT.

¿Entonces Que aprendimos?

  • Es posible que tenga un código optimizado para JIT, pero el compilador reorganiza su código en otra cosa
  • Los navegadores antiguos no tienen JIT pero siguen ejecutando tu código
  • El cierre compilado JS invoca menos llamadas de función al realizar una ejecución parcial de su código para funciones simples.

Entonces, ¿Qué haces?

  • Escribe funciones pequeñas y al punto, el compilador podrá manejarlas mejor
  • Si tiene un conocimiento muy profundo de JIT, optimice el código a mano y lo utilizó, el compilador de cierre puede no valer la pena.
  • Si desea que el código se ejecute un poco más rápido en navegadores antiguos, es una excelente herramienta
  • Las compensaciones generalmente valen la pena, pero solo tenga cuidado de revisar las cosas y no confiar ciegamente en ellas todo el tiempo.

En general, su código es más rápido. Puede introducir cosas que no les gusten a varios compiladores JIT, pero serán poco frecuentes si su código utiliza funciones más pequeñas y un diseño prototípico orientado a objetos correcto. Si piensa en el alcance completo de lo que está haciendo el compilador (descarga más corta Y ejecución más rápida), entonces cosas extrañas como var i = true, m = null, r = false; Puede ser un intercambio que vale la pena que el compilador haya creado a pesar de que se ejecutan más lentamente, la vida útil total fue más rápida.

También vale la pena notar que el cuello de botella más común en la ejecución de aplicaciones web es el modelo de Objeto de Documento, y le sugiero que ponga más esfuerzo allí si su código es lento.


Creo que habrá una penalización de rendimiento muy leve, pero es poco probable que importe mucho en los navegadores más nuevos y modernos.

Observe que las variables de alias estándar de Closure Compiler son todas variables globales. Lo que significa que, en un navegador antiguo donde el motor de JavaScript tarda un tiempo lineal para navegar por los ámbitos funcionales (por ejemplo, IE <9), cuanto más profundo esté dentro de las llamadas de función anidadas, más tiempo tardará en encontrar esa variable que contiene "verdadero" o " falso ", etc. Casi todos los motores de JavaScript modernos optimizan el acceso a las variables globales, por lo que esta penalización ya no debería ser válida en muchos casos.

Además, realmente no debería haber muchos lugares donde se vería "verdadero" o "falso" o "nulo" directamente en el código compilado, a excepción de las asignaciones o los argumentos. Por ejemplo: if (someFlag == true) ... se escribe principalmente if (someFlag) ... que compila el compilador en a && ... En su mayoría, solo los ve en asignaciones ( someFlag = true; ) y argumentos ( someFunc(true); ), que en realidad no ocurren con mucha frecuencia.

La conclusión es: aunque muchas personas dudan de la utilidad de los alias estándar de Closure Compiler (incluido yo), no debe esperar ningún impacto material en el rendimiento. Sin embargo, tampoco debe esperar ningún beneficio material en tamaños gzip.


Parece que en los navegadores modernos el uso de literal o null frente a una variable no hace absolutamente ninguna diferencia en casi todos los casos (como en cero; son exactamente iguales). En muy pocos casos, la variable es en realidad más rápida.

Entonces, esos bytes adicionales en el ahorro valen la pena y no cuestan nada.

true vs variable ( http://jsperf.com/true-vs-variable ):

null vs variable ( http://jsperf.com/null-vs-variable ):