parametro - funciones javascript en html
¿El uso de funciones anónimas afecta el rendimiento? (12)
¡SÍ! Las funciones anónimas son más rápidas que las funciones regulares. 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 la optimización de javascript y funciones anónimas aquí:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
Me he estado preguntando, ¿hay alguna 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;
}
La primera es más ordenada, ya que no satura su código con funciones poco utilizadas, pero ¿es importante que vuelva a declarar esa función varias veces?
@nickf
(Ojalá tuviera el representante para comentar, pero acabo de encontrar este sitio)
Mi punto es que aquí hay confusión entre las funciones nombradas / anónimas y el caso de uso de ejecutar + compilar en una iteración. Como lo ilustré, la diferencia entre anon + named es insignificante en sí misma; digo 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" (de las cuales el cambio constante de bloque + creación de objetos de este caso de uso es uno) y si no estás seguro, ¡prueba!
@nickf
Sin embargo, esa es una prueba bastante fatua, está comparando el tiempo de ejecución y compilación, que obviamente va a costar el método 1 (compila N veces, el motor JS depende) con el método 2 (compila una vez). No me puedo imaginar a un desarrollador de JS que pase 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 para su documento. El método de clic es más parecido al siguiente, que de hecho favorece levemente el método anon.
Usando un marco de prueba similar al tuyo:
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");
}
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: 142ms Prueba 2: 1983ms
Parece que el motor JS no reconoce que es la misma función en Test2 y la compila cada vez.
Como principio de diseño general, debe evitar implementar el 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 múltiples lugares.
Si (a diferencia de lo que deduces de tu pregunta) estás declarando la función interna una vez y usando ese código una vez (y no tienes nada más idéntico en tu programa) entonces una función anónoma probablemente (esa es una suposición) es tratada de la misma manera por el compilador como una función nombrada normal.
Es una característica muy útil en instancias específicas, pero no debe usarse en muchas situaciones.
Como se señala en los comentarios a la respuesta de @nickf: La respuesta a
Crear una función una vez más rápido que crearla un millón de veces
es simplemente sí Pero como muestra su perfil 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:
¿Cómo se compara una creación repetida + ejecución para crear una vez + ejecución repetida?
Si una función realiza un cálculo complejo, es probable que el tiempo para crear el objeto de función sea insignificante. Pero, ¿qué pasa con el exceso de crear 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 como se esperaba. Sin embargo, incluso con una operación muy rápida como un simple agregado, 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 que se mantiene un tiempo de ejecución insignificante, por ejemplo, si todo el cuerpo de la función se envuelve en un if (unlikelyCondition) { ... }
.
Donde podemos tener un impacto en el rendimiento está en la operación de declarar funciones. Aquí hay un punto de referencia para declarar funciones dentro del contexto de otra función o fuera de ella:
http://jsperf.com/function-context-benchmark
En Chrome, la operación es más rápida si declaramos la función afuera, pero en Firefox es todo lo contrario.
En otro ejemplo, vemos que si la función interna no es una función pura, también tendrá una falta de rendimiento en Firefox: http://jsperf.com/function-context-benchmark-3
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 un millar de objetos de función distintos aunque tengan el mismo cuerpo de código y no sean vinculantes para el alcance léxico ( closure ). Lo siguiente parece más rápido, por otro lado, porque simplemente asigna la misma referencia de función a los elementos del conjunto a lo largo del ciclo:
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
Si creara la función anónima antes de ingresar al bucle, entonces solo asigne referencias a ella a los elementos de la matriz mientras está dentro del bucle, encontrará que no hay ningún rendimiento o diferencia semántica alguna en comparación con la versión de 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 nombradas.
Como un aparte, puede parecer desde arriba que no hay diferencia entre:
function myEventHandler() { /* ... */ }
y:
var myEventHandler = function() { /* ... */ }
El primero es una declaración de función, mientras que el segundo es una asignación de variable a una función anónima. Aunque parezcan tener el mismo efecto, JavaScript los trata de forma ligeramente diferente. Para entender la diferencia, recomiendo leer, " Ambigüedad de declaración de función de JavaScript ".
El tiempo de ejecución real para cualquier enfoque va a estar dictado en gran medida por la implementación del compilador y el tiempo de ejecución del navegador. Para una comparación completa del rendimiento moderno del navegador, visite el sitio de JS Perf
Lo que definitivamente hará que su ciclo sea más rápido en una variedad de navegadores, especialmente los navegadores IE, se repite de la siguiente manera:
for (var i = 0, iLength = imgs.length; i < iLength; i++)
{
// do something
}
Has puesto un arbitrario 1000 en la condición de bucle, pero entiendes si querías revisar todos los elementos del conjunto.
Los objetos anónimos son más rápidos que los objetos nombrados. Pero llamar a más funciones es más costoso, y en un grado que eclipsa cualquier ahorro que pueda obtener al usar funciones anónimas. Cada función llamada se agrega a la pila de llamadas, lo que introduce una pequeña pero no trivial cantidad de gastos generales.
Pero a menos que esté escribiendo rutinas de cifrado / descifrado o algo similar que sea sensible al rendimiento, como muchos otros han señalado, siempre es mejor optimizar el código elegante y fácil de leer que el código rápido.
Suponiendo que está escribiendo un código bien estructurado, los problemas de velocidad deberían ser responsabilidad de quienes escriben los intérpretes / compiladores.
No esperaría mucha diferencia, pero si hay una, es probable que varíe según el motor de secuencias de comandos o el navegador.
Si encuentra que el código es más fácil de asimilar, el rendimiento no es un problema a menos que espere llamar a la función millones de veces.
una referencia casi siempre va a ser más lenta que lo que se refiere. Piénselo de esta manera: digamos que desea imprimir el resultado de agregar 1 + 1. Lo cual 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);
El segundo es una mejor práctica, incluso si tiene más líneas. Espero que todo esto sea útil. (y la sintaxis jquery no arrojó a nadie)