Undefined variable vs Undefined 属性 令人困惑的表现

Undefined variable vs Undefined property perplexing performance

我在做一些基准测试,发现了一些我似乎无法解释的荒谬结果。

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(b.a > 0) {
            return true;
        }
        else{
            return false;
        }
    })

测试结果:

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 %)
--------------------------------------------------------------------------

有人知道为什么第一种情况 Undefined variable 比另一种慢很多吗? 我在 jsbench 测试中发现了类似的性能结果:https://jsbench.me/vdku4ert4l/2

(此处为 V8 开发人员。)

比较undefined > 0总是有相同的性能。这里的区别在于,在您的一种情况下,V8 可以优化比较:对于像 b.a 这样的 属性 访问,它会记住所见对象的隐藏 class(即 b 的值);这就是称为“内联缓存”的技术的关键思想。

V8 将这个想法更进一步:如果所有遇到的对象都具有相同的隐藏 class,并且隐藏的 class 没有 a 属性 ,然后当该函数得到优化时,V8 会考虑该经验并生成优化的代码,该代码假设将来仍会如此,在这种情况下,它能够不断地折叠 属性 负载和比较。换句话说,它将函数优化为:

function undefined_property_optimized() {
  (if b.__hidden_class__ !== kPreviousHiddenClass) Deoptimize;
  return false;
}

其中 Deoptimize 表示:丢弃此优化代码并返回此函数的未优化代码(当然是在正确的点恢复执行)。

the first test Undefined variable is being heavily slowed down

不,它根本没有减速。 other 案例可以说是“作弊”。

adding const b = { a: undefined }; doesn't change anything

这实际上在很大程度上取决于您 运行 测试的准确程度。在本地测试中,对我强制引擎执行的操作进行了微小的修改,这个添加要么没有效果,要么使两个函数具有相同的速度。

经验法则 #1:当你 运行 一个微基准测试并且你看到每秒有几亿次操作时,优化编译器能够优化几乎所有的东西,而你正在测试一个空的(或微不足道的)功能。

经验法则 #2:微基准测试的结果很难正确解释。您可能认为您在这里测量 属性 负载,或者 > 0 比较;这两个假设都是不正确的:在更快的情况下,没有加载属性,也没有执行 > 0 比较。要理解微基准测试,您确实需要研究生成的机器代码(and/or 其他引擎内部),以确保它正在测试您认为正在测试的内容。

经验法则 #3:现代高性能 JavaScript 引擎是非常复杂的野兽,相同的 JS 片段 不会 总是具有相同的性能;它在很大程度上取决于它周围的代码(周围的行和应用中其他地方的远处代码都会影响它)。

经验法则 #4:微基准测试的结果几乎不会转移到实际代码中——主要是因为以上三个规则:-)


旁注:当您发现自己写作时:

if (some_condition) {
  return true;
} else {
  return false;
}

那么你可以用 return some_condition 替换它。可能不会更快,但会使您的代码更短。