¿Algún beneficio de rendimiento para "bloquear" objetos de JavaScript?
ecmascript-5 javascript-1.8 (7)
JavaScript 1.8.5 (ECMAScript 5) agrega algunos métodos interesantes que impiden futuras modificaciones de un objeto pasado, con diversos grados de minuciosidad:
Presumiblemente, el punto principal de esto es detectar errores: si sabe que no desea modificar un objeto después de un cierto punto, puede bloquearlo para que se produzca un error si, de forma inadvertida, intenta modificarlo más tarde. (Siempre que haya hecho "use strict";
es decir).
Mi pregunta: en los motores JS modernos como V8, ¿hay algún beneficio de rendimiento (por ejemplo, búsquedas de propiedades más rápidas, reducción de espacio en la memoria) al bloquear objetos utilizando los métodos anteriores?
(Véase también la bonita explicación de John Resig , aunque no menciona el rendimiento).
En Google Chrome (es decir, V8, es decir), un objeto congelado itera un 98% más lento que un objeto normal.
http://jsperf.com/performance-frozen-object
Test name* ops/sec
non-frozen object 32,193,471
frozen object 592,726
Probablemente esto se deba a que esas funciones son relativamente nuevas y probablemente no estén optimizadas todavía (pero esa es solo mi suposición, honestamente no sé la razón).
De todos modos, realmente no recomiendo usarlo por beneficios de rendimiento, ya que aparentemente no tiene sentido.
* El código para la prueba es:
var o1 = {a: 1};
var o2 = {a: 1};
Object.freeze(o2);
Prueba 1 (objeto no congelado):
for(var key in o1);
Prueba 2 (objeto congelado):
for(var key in o2);
EDITAR:
Desde que esta respuesta se escribió originalmente, el error en V8 que causó este problema se ha corregido. Vea la respuesta de Jan Molak arriba para mor
En teoría, congelar un objeto le permite ofrecer garantías más sólidas sobre la forma de un objeto.
Esto significa que la máquina virtual puede compactar el tamaño de la memoria.
Esto significa que la máquina virtual puede optimizar las búsquedas de propiedades en la cadena de prototipos.
Significa que cualquier referencia en vivo simplemente no se vive porque el objeto ya no puede cambiar.
En la práctica, los motores de JavaScript aún no realizan estas optimizaciones agresivas.
La única razón por la que veo estos métodos en el código de producción es que puede tener objetos sellados o congelados, por motivos de integridad.
Por ejemplo, escribo una pequeña biblioteca, que funciona muy bien y le ofrece un conjunto de métodos en un objeto, pero no quiero que cambie o sobrescriba ninguna de mis propiedades o métodos. No estoy diciendo que pueda evitar que hagas eso, pero puedo intentar evitar que lo hagas por accidente, lo que quizás sea más importante.
Además, esos métodos son fáciles de "calzar" en un entorno que no los conoce, simplemente devolviendo el objeto original. Por supuesto que no tendría efecto entonces.
No veo ninguna razón relacionada con el rendimiento para hacer esto.
No ha habido diferencias en el rendimiento desde al menos Chrome 47.0.2526.80 (64 bits).
Testing in Chrome 6.0.3359 on Mac OS 10.13.4
-----------------------------------------------
Test Ops/sec
non-frozen object 106,825,468 ±1.08% fastest
frozen object 106,176,323 ±1.04% fastest
Prueba de rendimiento (disponible en http://jsperf.com/performance-frozen-object ):
const o1 = {a: 1};
const o2 = {a: 1};
Object.freeze(o2);
// Non-frozen object:
for(var key in o1);
// Frozen object:
for(var key in o2);
Actualización 03.05.2018 : No hay diferencia en el rendimiento en Chrome 66.0.3359 (64 bits)
Actualización 06.03.2017 : No hay diferencia en el rendimiento en Chrome 56.0.2924 (64 bits)
Actualización 13.12.2015 : No hay diferencia en el rendimiento en Chrome 47.0.2526.80 (64 bits)
Con Chrome 34, un objeto congelado se desempeña ligeramente mejor que uno no congelado en el caso de prueba de @ pimvdb (resultados a continuación). Sin embargo, la diferencia no parece ser lo suficientemente grande como para justificar el uso de esta técnica para obtener beneficios de rendimiento.
http://jsperf.com/performance-frozen-object
Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test Ops/sec
non-frozen object 105,250,353 ±0.41% 3% slower
frozen object 108,188,527 ±0.55% fastest
La ejecución de los casos de prueba de @ kangax muestra que ambas versiones del objeto se comportan de manera muy parecida:
http://jsperf.com/performance-frozen-object-prop-access
Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test Ops/sec
non-frozen object 832,133,923 ±0.26% fastest
frozen object 832,501,726 ±0.28% fastest
http://jsperf.com/http-jsperf-com-performance-frozen-object-instanceof
Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test Ops/sec
non-frozen object 378,464,917 ±0.42% fastest
frozen object 378,705,082 ±0.24% fastest
Según el problema de Google Code :
La diferencia de rendimiento se debe a la estructura de datos de la tienda de respaldo. Para algunas propiedades, el descriptor de objeto describe dónde se almacenan las propiedades, en una matriz de propiedades. Si el número de propiedades aumenta, eventualmente cambiamos a un diccionario para el almacén de respaldo, que es menos eficiente, pero más flexible. Cuando congelamos un objeto, lo que se está haciendo es que todas las propiedades se configuran como no configurables y no grabables. Almacenar esos atributos solo es posible en una tienda de respaldo de diccionarios, así que cambiamos a eso.
EDITAR: Se ha trabajado más para optimizar esto y la diferencia entre los objetos normales y los objetos congelados se ha reducido a aproximadamente el 20%. Los objetos sellados todavía toman el doble de tiempo para iterar pero se está trabajando en esto.
Si está interesado en el rendimiento de la creación de objetos (literal vs congelado vs sellado vs Immutable.Map
), he creado una prueba en jsPerf para verificarlo.
Hasta ahora, solo he tenido la oportunidad de probarlo en Chrome 41 y Firefox 37. En ambos navegadores, la creación de un objeto congelado o sellado lleva aproximadamente tres veces más que la creación de un literal, mientras que el Immutable.Map
realiza aproximadamente 50 Tiempos peores que el literal.
V8 ha optimizado Object.freeze a partir del 20 de junio de 2013. Y Object.seal y Object.preventExtensions a partir del 10 de diciembre de 2014. Ver número https://code.google.com/p/chromium/issues/detail?id= 115960