2012-03-19 16 views
21

Estoy viendo http://www.youtube.com/watch?v=mHtdZgou0qU, y alrededor de las 13:37 (jeje), muestra una diapositiva de una lista de cosas que evitar debido a la adición de un nuevo objeto en la cadena de alcance.Javascript - Use cierres con moderación?

Entiendo lo que dice con las declaraciones using y try-catch, así como el acceso a variables fuera del alcance, pero no entiendo por qué deberían evitarse los cierres. Si las variables locales del cierre van a estar en la parte superior de la cadena de alcance, ¿dónde está la pérdida de rendimiento?

+2

Solo recuerde: la optimización prematura es la raíz de todo mal. El video trata sobre hacer que JavaScript sea más eficiente, sin embargo, la mayoría de JavaScript nunca necesita ser optimizado. Si tiene una llamada a una función configurada de forma asincrónica después de que un usuario hace clic en un botón, el usuario nunca notará la diferencia entre una tasa de respuesta de 30 ms y una tasa de respuesta de 40 ms. – zzzzBov

+1

Las respuestas aquí son todas buenas. Recuerde, sin embargo, que el video tiene un par de años, y puede no ser tan relevante como lo fue el t. –

Respuesta

20

Es porque, para buscar variables que no son locales, la máquina virtual debe recorrer la cadena del alcance para encontrarlas. Las variables locales, por otro lado, se almacenan en caché, por lo que una búsqueda de variables locales es mucho más rápida. Cuanto más anidada es una función, más larga se vuelve la cadena de alcance y más aumenta el impacto potencial en el rendimiento.

Esto es en parte por qué a menudo se ve código como este en las bibliotecas populares JS:

(function(window, document, undefined) { 
    // ... 
})(window, document); 

Aquí, window y document variables locales se convierten, así que mirando hacia arriba se convierte en mucho más rápido, que se convierte en bastante notable si se hace referencia estos objetos miles de veces desde dentro de su código.

This page tiene una descripción muy detallada de las cadenas de alcance y contextos de ejecución. (Todo el artículo es interesante si tiene tiempo para leerlo).

En general, sin embargo, los navegadores modernos optimizan todas estas cosas hasta el punto de que son básicamente insignificantes, por lo que no es algo de lo que me preocupe.

+0

Esto es correcto, porque los cierres almacenan referencias a las variables locales en lugar de a las copias, por lo que obliga a una pila a recorrer en lugar de a una búsqueda local. –

+0

Me refiero a un cierre que no tiene acceso a variables fuera del alcance. Parecía un poco redundante para él decir para evitar el acceso a variables fuera del alcance, y luego explícitamente decir evitar cierres. Parece implicado que quiere decir, además de usar variables locales, que también debe evitar los cierres. ¿Estoy malinterpretando lo que dice? – mowwwalker

+2

@ Walkerneo: No es un cierre si no hace referencia a variables no locales. Lo que está diciendo es que debes evitar los cierres siempre que sea posible, pero cuando * tienes * para referenciar una variable fuera del alcance, debes usar una variable local para hacer la búsqueda más rápida (si usas la variable a menudo desde dentro de esa función) -de otra manera no hará mucho). –

9

The linked video explains why closure can inflict some performance hits starting about 11:08.

Básicamente, él está diciendo que para cada función anidada, se agrega otro objeto a la cadena de ámbito y por lo tanto el acceso a las variables exterior del cierre se llevará más tiempo.

Para encontrar el valor asociado a una variable, el interprer Javascript sigue este proceso:

  1. buscar el objeto ámbito local
  2. si 1 no funcionó, buscar el objeto ámbito padre
  3. si 2 no funciona, búsqueda de objetos ámbito primario de los padres
  4. seguir buscando ámbitos principales hasta
  5. se busca el ámbito global
  6. y si aún no se encuentra, arroje un error variable indefinido.

En una función normal, para encontrar una variable, solo tiene que buscar en la parte superior de la cadena de ámbito. Un cierre, por otro lado, para encontrar variables padre tendrá que buscar en la cadena del alcance, a veces varios niveles de profundidad. Por ejemplo, si usted tenía algunos cierres de este tipo (tenga en cuenta que este es un ejemplo muy artificiosa):

function a (x) { 
    function b (y) { 
    return (function (z) { 
     return x + y + z; 
    })(y + y); 
    } 
    return b(x + 3); 
} 

De la función más interna, para evaluar la expresión x + y + z, tiene que recorrer hasta tres niveles en el cadena de alcance para encontrar x, luego tiene que atravesar la cadena del alcance dos niveles para encontrar y, finalmente, una vez para encontrar z.En total, tuvo que buscar seis objetos en la cadena de alcance para devolver el resultado final.

Esto es inevitable en los cierres, porque cierres siempre tienen que acceder a las variables principales. Si no lo hicieran, no tendría sentido usar un cierre.

También tenga en cuenta que en Javascript, hay una sobrecarga significativa en la creación de funciones, especialmente cierres. Tomemos, por ejemplo, este bastante simple cierre:

function a(x) { 
    return function (y) { 
    return x + y; 
    } 
} 

Y usted lo llama varias veces diferentes, como este

var x = a(1); 
var y = a(2); 
var z = a(3); 
alert(x(3)); // 4 
alert(y(3)); // 5 
alert(z(3)); // 6 

Se dará cuenta de que la función de regresar de a tiene que mantener lo que pasó como argumento en la función primaria incluso después de que ya se haya llamado a la función padre. Esto significa que el intérprete debe mantener en la memoria lo que pasó en cada función que ha llamado hasta ahora.

+0

¿Guardaría 'y'' 'z' como variables locales en la tercera función aún reduce el rendimiento? Por supuesto, para este ejemplo, no hay una razón para crear los cierres, pero ¿qué ocurre cuando hay? – mowwwalker

+0

@Walkerneo Todavía tendrá que ir por la cadena del alcance para encontrar las variables principales. Si usa las variables principales más de una vez en la función interna, valdrá la pena declararlas como variables locales, pero si solo las usa una vez, no hay nada de útil en declararlas como variables locales. –

+0

Bien, entiendo el problema de atravesar la cadena de alcance, pero, como dije en mi comentario sobre la otra respuesta, la forma en que usó "usar cierres con moderación" justo después de lo que dice sobre las variables fuera del alcance hace que parezca como que hay algo intrínsecamente incorrecto en los cierres y no solo que agreguen otro objeto a la cadena de alcance. – mowwwalker

Cuestiones relacionadas