Me he estado preguntando, ¿existe una diferencia de rendimiento entre el uso de funciones con nombre y funciones anónimas en Javascript?
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = function() {
// do something
};
}
vs
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
El primero es más ordenado, ya que no abarrota su código con funciones que rara vez se utilizan, pero ¿importa que vuelva a declarar esa función varias veces?
Respuestas:
El problema de rendimiento aquí es el costo de crear un nuevo objeto de función en cada iteración del ciclo y no el hecho de que use una función anónima:
for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = function() { // do something }; }
Está creando mil objetos de función distintos a pesar de que tienen el mismo cuerpo de código y no se vinculan al ámbito léxico ( cierre ). Lo siguiente parece más rápido, por otro lado, porque simplemente asigna la misma referencia de función a los elementos de la matriz en todo el ciclo:
function myEventHandler() { // do something } for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = myEventHandler; }
Si tuviera que crear la función anónima antes de ingresar al bucle, entonces solo asigne referencias a los elementos de la matriz mientras está dentro del bucle, encontrará que no hay diferencia de rendimiento o semántica en comparación con la versión de la función nombrada:
var handler = function() { // do something }; for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = handler; }
En resumen, no hay un costo de rendimiento observable al usar funciones anónimas sobre funciones nombradas.
Como acotación al margen, puede parecer desde arriba que no hay diferencia entre:
function myEventHandler() { /* ... */ }
y:
var myEventHandler = function() { /* ... */ }
La primera es una declaración de función, mientras que la última es una asignación variable a una función anónima. Aunque parezca que tienen el mismo efecto, JavaScript los trata de manera ligeramente diferente. Para comprender la diferencia, recomiendo leer, " Ambigüedad de declaración de función de JavaScript ".
El tiempo de ejecución real de cualquier enfoque dependerá en gran medida de la implementación del compilador y el tiempo de ejecución del navegador. Para obtener una comparación completa del rendimiento del navegador moderno, visite el sitio JS Perf
fuente
node.js
aplicaciones web, es mejor crear las funciones fuera del flujo de solicitud y pasarlas como devoluciones de llamada, que crear devoluciones de llamada anónimas?Aquí está mi código de prueba:
var dummyVar; function test1() { for (var i = 0; i < 1000000; ++i) { dummyVar = myFunc; } } function test2() { for (var i = 0; i < 1000000; ++i) { dummyVar = function() { var x = 0; x++; }; } } function myFunc() { var x = 0; x++; } document.onclick = function() { var start = new Date(); test1(); var mid = new Date(); test2(); var end = new Date(); alert ("Test 1: " + (mid - start) + "\n Test 2: " + (end - mid)); }
Los resultados:
Prueba 1: 142 ms Prueba 2: 1983 ms
Parece que el motor JS no reconoce que es la misma función en Test2 y la compila cada vez.
fuente
Como principio de diseño general, debe evitar la implementación del mismo código varias veces. En su lugar, debe extraer el código común en una función y ejecutar esa función (general, bien probada, fácil de modificar) desde varios lugares.
Si (a diferencia de lo que infiere de su pregunta) está declarando la función interna una vez y usando ese código una vez (y no tiene nada más idéntico en su programa), entonces una función anónima probablemente (eso es una suposición) será tratada de la misma manera por el compilador como una función con nombre normal.
Es una característica muy útil en casos específicos, pero no debería usarse en muchas situaciones.
fuente
No esperaría mucha diferencia, pero si hay una, probablemente variará según el motor de secuencias de comandos o el navegador.
Si encuentra el código más fácil de asimilar, el rendimiento no es un problema a menos que espere llamar a la función millones de veces.
fuente
Donde podemos tener un impacto en el rendimiento es en la operación de declaración de funciones. Aquí hay un punto de referencia para declarar funciones dentro del contexto de otra función o fuera:
http://jsperf.com/function-context-benchmark
En Chrome el funcionamiento es más rápido si declaramos la función en el exterior, pero en Firefox es todo lo contrario.
En otro ejemplo vemos que si la función interna no es una función pura, tendrá una falta de rendimiento también en Firefox: http://jsperf.com/function-context-benchmark-3
fuente
Lo que definitivamente hará que su bucle sea más rápido en una variedad de navegadores, especialmente los navegadores IE, es el siguiente bucle:
for (var i = 0, iLength = imgs.length; i < iLength; i++) { // do something }
Ha puesto un 1000 arbitrario en la condición de bucle, pero obtiene mi deriva si desea revisar todos los elementos de la matriz.
fuente
una referencia casi siempre será más lenta que la cosa a la que se refiere. Piénselo de esta manera: digamos que desea imprimir el resultado de sumar 1 + 1. Lo que tiene más sentido:
alert(1 + 1);
o
a = 1; b = 1; alert(a + b);
Me doy cuenta de que es una forma realmente simplista de verlo, pero es ilustrativo, ¿verdad? Use una referencia solo si se va a usar varias veces, por ejemplo, cuál de estos ejemplos tiene más sentido:
$(a.button1).click(function(){alert('you clicked ' + this);}); $(a.button2).click(function(){alert('you clicked ' + this);});
o
function buttonClickHandler(){alert('you clicked ' + this);} $(a.button1).click(buttonClickHandler); $(a.button2).click(buttonClickHandler);
La segunda es una mejor práctica, incluso si tiene más líneas. Ojalá todo esto sea de ayuda. (y la sintaxis de jquery no confundió a nadie)
fuente
@nickf
(Ojalá tuviera el representante para comentar, pero acabo de encontrar este sitio)
Mi punto es que hay confusión aquí entre funciones nombradas / anónimas y el caso de uso de ejecutar + compilar en una iteración. Como ilustré, la diferencia entre anon + named es insignificante en sí misma; estoy diciendo que es el caso de uso el que está defectuoso.
Me parece obvio, pero si no, creo que el mejor consejo es "no hagas tonterías" (uno de los cuales es el cambio constante de bloques + la creación de objetos de este caso de uso) y, si no estás seguro, ¡prueba!
fuente
¡SI! Las funciones anónimas son más rápidas que las funciones normales. Quizás si la velocidad es de suma importancia ... más importante que la reutilización del código, entonces considere usar funciones anónimas.
Hay un artículo realmente bueno sobre cómo optimizar javascript y funciones anónimas aquí:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
fuente
Los objetos anónimos son más rápidos que los objetos con nombre. Pero llamar a más funciones es más caro y hasta un punto que eclipsa cualquier ahorro que pueda obtener mediante el uso de funciones anónimas. Cada función llamada se suma a la pila de llamadas, lo que introduce una pequeña pero no trivial cantidad de sobrecarga.
Pero a menos que esté escribiendo rutinas de cifrado / descifrado o algo similarmente sensible al rendimiento, como muchos otros han señalado, siempre es mejor optimizar para un código elegante y fácil de leer en lugar de un código rápido.
Suponiendo que está escribiendo un código bien diseñado, los problemas de velocidad deberían ser responsabilidad de quienes escriben los intérpretes / compiladores.
fuente
@nickf
Sin embargo, esa es una prueba bastante fatua, está comparando el tiempo de ejecución y compilación allí, lo que obviamente va a costar el método 1 (compila N veces, dependiendo del motor JS) con el método 2 (compila una vez). No puedo imaginar a un desarrollador de JS que pasaría su código de escritura de prueba de esa manera.
Un enfoque mucho más realista es la asignación anónima, ya que de hecho está utilizando el método document.onclick es más parecido al siguiente, que de hecho favorece levemente el método anon.
Usando un marco de prueba similar al suyo:
function test(m) { for (var i = 0; i < 1000000; ++i) { m(); } } function named() {var x = 0; x++;} var test1 = named; var test2 = function() {var x = 0; x++;} document.onclick = function() { var start = new Date(); test(test1); var mid = new Date(); test(test2); var end = new Date(); alert ("Test 1: " + (mid - start) + "ms\n Test 2: " + (end - mid) + "ms"); }
fuente
Como se señaló en los comentarios a la respuesta de @nickf: La respuesta a
es simplemente sí. Pero como muestra su rendimiento JS, no es más lento en un factor de un millón, lo que demuestra que en realidad se vuelve más rápido con el tiempo.
La pregunta más interesante para mí es:
Si una función realiza un cálculo complejo, el tiempo necesario para crear el objeto de función probablemente sea insignificante. Pero, ¿qué pasa con los gastos generales de creación en los casos en que la ejecución es rápida? Por ejemplo:
// Variant 1: create once function adder(a, b) { return a + b; } for (var i = 0; i < 100000; ++i) { var x = adder(412, 123); } // Variant 2: repeated creation via function statement for (var i = 0; i < 100000; ++i) { function adder(a, b) { return a + b; } var x = adder(412, 123); } // Variant 3: repeated creation via function expression for (var i = 0; i < 100000; ++i) { var x = (function(a, b) { return a + b; })(412, 123); }
Este JS Perf muestra que crear la función solo una vez es más rápido de lo esperado. Sin embargo, incluso con una operación muy rápida como una simple adición, la sobrecarga de crear la función repetidamente es solo un pequeño porcentaje.
La diferencia probablemente solo se vuelve significativa en los casos en que la creación del objeto de función es compleja, mientras se mantiene un tiempo de ejecución insignificante, por ejemplo, si todo el cuerpo de la función está envuelto en un
if (unlikelyCondition) { ... }
.fuente