Estaba haciendo una evaluación comparativa y encontré algunos resultados absurdos que parece que no puedo explicar.
const a = undefined; const b = {}; // add tests suite .add('Undefined variable', function () { if(a > 0){ return true; } else{ return false; } }) .add('Undefined property', function () { if(ba > 0) { return true; } else{ return false; } })Resultados de la prueba:
Undefined variable x 69,660,401 ops/sec ±2.48% (36 runs sampled) Undefined property x 994,939,175 ops/sec ±0.85% (40 runs sampled) Test Results -------------------------------------------------------------------------- Undefined property : 994939174.67 ops/sec (+1328.27 %) Undefined variable : 69660400.51 ops/sec ( +0.00 %) -------------------------------------------------------------------------- ¿Alguien tiene alguna idea de por qué la Undefined variable del primer caso es mucho más lenta que la otra? Encontré resultados de rendimiento similares en una prueba jsbench: https://jsbench.me/vdku4ert4l/2
(Desarrollador V8 aquí.)
Comparar undefined > 0 siempre tiene el mismo rendimiento. La diferencia aquí es que en uno de sus casos, V8 puede optimizar la comparación: para un acceso de propiedad como ba , recuerda la clase oculta de los objetos vistos (es decir, los valores de b ); esa es la idea clave de la técnica llamada "almacenamiento en caché en línea".
V8 lleva esta idea un paso más allá: si todos los objetos encontrados tuvieran la misma clase oculta, y esa clase oculta no tuviera a propiedad, entonces cuando esa función se optimiza, V8 toma esa experiencia en cuenta y produce un código optimizado que asume que este seguirá siendo el caso en el futuro, lo que en este caso le permite eliminar constantemente la carga de propiedades y la comparación. En otras palabras, optimiza esa función a algo como:
function undefined_property_optimized() { (if b.__hidden_class__ !== kPreviousHiddenClass) Deoptimize; return false; } Donde Deoptimize significa: descartar este código optimizado y volver al código no optimizado para esta función (reanudando la ejecución exactamente en el punto correcto, por supuesto).
la primera prueba La
Undefined variablese está ralentizando mucho
No, no se está ralentizando en absoluto. El otro caso es "hacer trampa", por así decirlo.
agregando
const b = { a: undefined };no cambia nada
En realidad, eso depende mucho de cómo ejecute exactamente la prueba. En las pruebas locales, con modificaciones menores a lo que fuerzo al motor a hacer, esta adición no tiene efecto o hace que ambas funciones tengan la misma velocidad.
Regla general #1: cuando ejecuta un microbenchmark y ve varios cientos de millones de operaciones por segundo, entonces el compilador de optimización pudo optimizar casi todo, y está probando una función vacía (o trivial).
Regla general #2: los resultados de los microbenchmarks son difíciles de interpretar correctamente. Es posible que haya pensado que estaba midiendo cargas de propiedad aquí, o > 0 comparaciones; ambas suposiciones serían incorrectas: en el caso más rápido, no se están cargando propiedades y no se están realizando comparaciones > 0 . Para dar sentido a un micropunto de referencia, realmente necesita estudiar el código de máquina generado (y/u otras partes internas del motor), para asegurarse de que está probando lo que cree que está probando.
Regla general n.º 3: los motores JavaScript modernos de alto rendimiento son bestias increíblemente complejas, y el mismo fragmento de JS no siempre tendrá el mismo rendimiento; depende en gran medida del código que lo rodea (tanto las líneas que lo rodean inmediatamente como el código lejano en otra parte de su aplicación pueden afectarlo).
Regla general #4: los resultados de los microbenchmarks casi nunca se transfieren al código del mundo real, principalmente debido a las tres reglas anteriores :-)
Nota al margen: cuando te encuentres escribiendo:
if (some_condition) { return true; } else { return false; } entonces puedes reemplazar eso con return some_condition . Probablemente no sea más rápido, pero hace que su código sea más corto.