Pregunta

Me he estado preguntando, ¿hay 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 el más ordenado, ya que no se acumulen en su código con muy rara funciones, pero ¿importa que usted está re-declarar que la función varias veces?

¿Fue útil?

Solución

El problema aquí es el costo de crear un nuevo objeto de la función en cada iteración del bucle, y no el hecho de que usted use una función anónima:

for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = function() {
        // do something    
    };
}

Usted es la creación de un millar de distintas función de los objetos, incluso a pesar de que tienen el mismo cuerpo de código y no vinculante para el ámbito léxico (cierre).El siguiente parece más rápido, por otro lado, porque simplemente asigna el mismo la función de referencia a los elementos de la matriz a lo largo del bucle:

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

Si se va a crear la función anónima antes de entrar en el bucle, a continuación, asignar referencias a los elementos de la matriz, mientras que en el interior del bucle, usted encontrará que no hay ningún rendimiento o semántica diferencia alguna cuando se compara con el nombre de la versión de función:

var handler = function() {
    // do something    
};
for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = handler;
}

En resumen, no es observable costo de rendimiento para el uso anónimo a través de nombre de funciones.

Como un aparte, puede parecer de lo anterior que no hay ninguna diferencia entre:

function myEventHandler() { /* ... */ }

y:

var myEventHandler = function() { /* ... */ }

El primero es un declaración de la función mientras que el segundo es una asignación de variable a una función anónima.A pesar de que puede parecer tener el mismo efecto, JavaScript no tratarlos de forma ligeramente diferente.Para entender la diferencia, recomiendo la lectura, "Función de JavaScript declaración de la ambigüedad”.

El momento de ejecución para cualquier enfoque es en gran medida va a ser dictada por el navegador de la aplicación de la ejecución y el compilador.Para una comparación completa de las modernas rendimiento del navegador, visite el JS Perf sitio

Otros consejos

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 JS motor no reconocer que se trata de la misma función en Test2 y compila cada vez.

Como un general principio de diseño, se debe evitar implimenting el mismo código varias veces.En lugar usted debe levantar común de código en una función y lo ejecuta (en general, bien probado, fácil de modificar) la función de múltiples lugares.

Si (a diferencia de lo que se desprende de tu pregunta) que se está declarando la función interna de una vez y utilizar el código de una vez (y no tiene nada idénticas en su programa), a continuación, un anonomous función probablemente (eso es una suposición de la gente) sea tratada de la misma manera por el compilador como una normal nombre de la función.

Su una característica muy útil en casos específicos, pero no debe ser utilizado en muchas situaciones.

Yo no esperaría mucho la diferencia, pero si hay uno, es probable que varían según el motor de secuencias de comandos o navegador.

Si usted encuentra que el código sea más fácil de asimilar, el rendimiento no es un problema a menos que usted espera para llamar a la función millones de veces.

Objetos anónimos que son más rápidos que los objetos con nombre.Pero llamar a más funciones, es más caro, y a un grado que eclipsa a cualquier ahorro que se puede obtener del uso de funciones anónimas.Cada función llamada añade a la pila de llamada, la cual introduce un pequeño pero no trivial de la cantidad de sobrecarga.

Pero a menos que usted está escribiendo el cifrado/descifrado de rutinas o algo similar sensibles al rendimiento, como muchos otros, han observado que siempre es mejor para optimizar elegante, fácil-a-lea el código más rápido de código.

Suponiendo que usted está escribiendo así de arquitectura de código, a continuación, los problemas de velocidad debe ser la responsabilidad de los que escriben los intérpretes/compiladores.

Donde podemos tener un impacto en el rendimiento es en la operación de la declaración de funciones.Aquí es un punto de referencia de declarar funciones dentro del contexto de otra función o en el exterior:

http://jsperf.com/function-context-benchmark

En Chrome, la operación es más rápida si declaramos la función fuera, pero en Firefox es todo lo contrario.

En otro ejemplo podemos ver que si el interior de la función no es una función pura, tendrá una falta de rendimiento también en Firefox:http://jsperf.com/function-context-benchmark-3

Lo que sin duda harán de su lazo más rápido a través de una variedad de navegadores, especialmente los navegadores IE, es un bucle como el siguiente:

for (var i = 0, iLength = imgs.length; i < iLength; i++)
{
   // do something
}

Te lo he puesto en un arbitrario 1000 en la condición de bucle, pero me entiendes si quería ir a través de todos los elementos de la matriz.

una referencia es casi siempre va a ser más lento que la cosa es referida.Piénsalo de esta manera - digamos que usted quiere imprimir el resultado de la suma de 1 + 1.Lo que hace más sentido:

alert(1 + 1);

o

a = 1;
b = 1;
alert(a + b);

Me doy cuenta de que es realmente un modo simplista de verlo, pero es ilustrativo, a la derecha?El uso de una referencia sólo si va a ser utilizado varias veces - por ejemplo, que 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 la mejor práctica, incluso si tiene más líneas.Esperemos que todo esto es de gran ayuda.(y la sintaxis de jquery no tirar a nadie fuera)

@nickf

(deseo que yo tenía de la rep comentar, pero sólo he encontrado este sitio)

Mi punto es que hay una confusión entre el nombre/funciones anónimas y el caso de uso de la ejecución de + compilar en una iteración.Como he ilustrado, la diferencia entre anon+nombre es insignificante en sí mismo - estoy diciendo que es el caso de uso que es defectuoso.

Me parece obvio, pero si no yo creo que el mejor consejo es "no hagas tonterías" (de la que el constante cambio de bloque + objeto la creación de este caso de uso es uno de ellos) y si no estás seguro, prueba!

SÍ!Las funciones anónimas son más rápidas que las funciones regulares.Tal vez si la velocidad es de suma importancia...más importante que la reutilización de código, a continuación, considere el uso de funciones anónimas.

Hay un artículo muy bueno sobre la optimización de javascript y funciones anónimas aquí:

http://dev.opera.com/articles/view/efficient-javascript/?page=2

@nickf

Que un fatuo de la prueba, sin embargo, usted está comparando la ejecución y la compilación tiempo allí, lo cual es, obviamente, va a costar el método 1 (compila N veces, JS motor de función) con el método 2 (compila una vez).No me puedo imaginar un JS desarrollador que iba a pasar a su libertad condicional en la escritura del código de tal manera.

Con mucho, un enfoque más realista es el encargo anónimo, como en el hecho de que está utilizando para el documento.método onclick es más parecida a la siguiente, que, de hecho, ligeramente favorece el anon método.

El uso de una prueba similar marco a la tuya:


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");
}

Como se señaló en los comentarios de @nickf respuesta:La respuesta a

Es la creación de una función una vez más rápida de crear un millón de veces

es simplemente sí.Pero como su JS perf muestra, que no es más lento por un factor de un millón, lo que demuestra que en realidad se llega más rápido a lo largo del tiempo.

La pregunta más interesante para mí es:

¿Cómo se repite crear + ejecutar comparar a crear una vez + repetido ejecutar.

Si una función tiene un complejo cálculo el tiempo para crear el objeto de la función es probablemente insignificante.Pero, ¿qué acerca de la cabeza de crear en los casos donde ejecutar es rápido?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 la creación de la función de una sola vez es más rápido como se esperaba.Sin embargo, incluso con una operación muy rápida, como un simple complemento, la sobrecarga de la creación de la función repetidamente, es sólo un pequeño tanto por ciento.

La diferencia probablemente sólo llega a ser significativa en los casos donde la creación de la función de objeto es complejo, mientras que el mantenimiento de un insignificante de tiempo de ejecución, por ejemplo, si todo el cuerpo de la función es envuelta en una if (unlikelyCondition) { ... }.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top