2012-09-30 23 views
10

A menudo tengo argumentos opcionales en las funciones, pero algunas pruebas muestran un gran rendimiento para ellos en Firefox y Safari (70-95%). Extrañamente, si paso en el valor literal undefined, entonces no hay ninguna penalización. ¿Qué podría estar pasando aquí? No hubiera pensado que era una cuestión de cadena de alcance, ya que son intrínsecamente locales para la función. ¿Debo comenzar a pasar undefined en cada argumento opcional?Penalización de rendimiento para argumentos indefinidos

jsPerf: http://jsperf.com/function-undefined-args/2

+5

@MattWhipple - Esa es una publicación interesante, pero ¿qué tiene que ver con la pregunta de OP? (Buena pregunta, por cierto, @robC.) –

+0

Este es un hallazgo interesante.Antes de cambiar todo el código para completar todos los argumentos, verificaría si hay un informe de errores abierto para esas implementaciones de JS, y si no es el archivo uno. –

+0

Sospecho fuertemente que el tiempo de ejecución está delimitando las funciones cuando hay una coincidencia de conteo de parámetros, pero de lo contrario ejecuta la función como una función real. El hecho de que nada haga uso del valor de retorno de la función puede significar que el tiempo de ejecución no * nada * cuando los parámetros están completamente suministrados. – Pointy

Respuesta

5

Para una función como esta:

function threeArgs(x, y, z) { 
    return x + y + z; 
} 

que se llama así:

threeArgs(1, 2, 3); 

el optimizador es libre de tomar la decisión de generar ningún código en absoluto. Es bastante fácil para él determinar que no hay efectos secundarios, porque la función simplemente hace referencia a sus valores de parámetros y devuelve el resultado de una expresión simple. Como se ignora el valor de retorno, no hay ninguna razón para que el tiempo de ejecución haga nada.

Más allá de eso, si el código fueron:

something += threeArgs(1, 2, 3); 

el optimizador puede decidir generar código más o menos equivalente a:

something += 6; 

¿Por qué? Porque la llamada se realizó con constantes numéricas, y puede doblarlas en el momento de generación de código. Puede ser conservador en eso, porque los números son raros, pero aquí están todos enteros, así que bien podría hacer esto. Incluso si no lo hiciera, podría inline con seguridad la función:

something += 1 + 2 + 3; 

Cuando hay un parámetro que falta, sin embargo, puede ser que el optimizadores de la fianza y generar una llamada a la función real. Para una función tan simple, la sobrecarga de la llamada de función podría explicar fácilmente una gran diferencia en el rendimiento.

Al usar variables en lugar de constantes en una prueba, y al usar realmente el valor de retorno de la función, puede "confundir" el optimizador y evitar que se salte la llamada o pre-calcule el resultado, pero puede hacerlo ' t evitar que forme parte de la línea. Todavía creo que su resultado es interesante por esa razón: expone el hecho de que (a partir de hoy de todos modos) esos optimizadores son sensibles a la forma en que se invocan las funciones.

+2

Esto parece una explicación plausible, pero ¿cómo sabemos que esto es realmente lo que está sucediendo? – jfriend00

+0

Los resultados de FF y el último Chrome están tan por delante del campo que solo se puede reducir a optimizaciones. La llamada de función que conlleva una penalización tiene en realidad el mismo rendimiento que otros navegadores no optimizados. – robC

+0

"Sin embargo, cuando falta un parámetro, es posible que los optimizadores rescaten", ¿podría explicar por qué? Si falta un argumento, está garantizado que no está definido, por lo que a mí me parece que simplemente alineará '1 + 2 + undefined'. – pimvdb

2

Creo que lo que podría explicar la diferencia de rendimiento es la forma argumentos se pasan a un objeto función: a través del objeto arguments. Cuando no pasa ningún argumento, JS comenzará escaneando el objeto de argumentos para cualquiera de los argumentos dados, cuando no están definidos, se escaneará la cadena de prototipos arguments, hasta llegar al Object.prototype. Si todos carecen de la propiedad deseada, JS devolverá undefined. Considerando que, pasando definido de forma explícita, la establece como una propiedad directamente en los argumentos del objeto:

function foo(arg) 
{ 
    console.log(arguments.hasOwnProperty('0')); 
} 
foo();//false' 
foo('bar');//true 
foo(undefined);//true 

deduzco que esa es la razón por la que pasa sin definir explícitamente tiende a ser más rápido.

+4

Esta es una idea interesante, pero me parece que dado que el símbolo "arg" se declara en la lista de parámetros formales, * siempre * será una referencia local. – Pointy

+0

Tal vez, pero cambiar la función a 'console.log (arg === arguments [0]);' y llamar a 'foo (new Date())' logs verdadero, por lo que ambos hacen referencia exactamente a lo mismo. De hecho, diría que args es una referencia local a una propiedad del objeto 'arguments' local. Alcance de escaneo a un lado, los argumentos del prototipo aún se mantiene, ¿no? –

+2

Oh, sí, estoy de acuerdo con eso: el objeto 'arguments' es extraño. No estoy seguro exactamente cómo afectaría esto, es lo que quise decir. En otras palabras, como "arg" es un parámetro formal, entonces su valor es * siempre * el valor de 'argumentos [0]', ya sea 'indefinido' o no. – Pointy

Cuestiones relacionadas