【问题标题】:Why is checking void 0 so much faster than checking undefined?为什么检查 void 0 比检查 undefined 快得多?
【发布时间】:2017-11-30 03:29:40
【问题描述】:

在我的级联 javascript 上使用 gulp-uglify 后,我注意到了一些有趣的事情。我将undefined 传递给全局IIFE 包装器,我看到它正在将其更改为void 0。 void 0 到底是什么?我在控制台中运行它并返回未定义。有趣的!这让我很好奇,所以我开始在 void 0 上运行测试。在我的控制台测试(简单循环和时间戳)中,我观察到速度提高了 180 倍,具体取决于浏览器,检查 void 0 而不是 undefined。有谁知道为什么检查 void 0 这么快?

(function(start, x, z){
    for (var i=0; i<z; i++){
      if (x === undefined){}
    }
    console.info('t1 ', Date.now() - start);
    start = Date.now();
    for (var i=0; i<z; i++){
      if (x === void 0){}
    }
    console.info('t1 ', Date.now() - start);
})(Date.now(), '', 1e6)

【问题讨论】:

  • 不,void 0 是原语,undefined 是全局变量。
  • undefined 是一个原语,但在使用标识符时是通过全局变量访问的。
  • 总体而言,以大量盐分进行微基准测试。他们很难做到正确。一个单一的测试不应该太有说服力。而且我认为大多数实现可以静态确定全局undefined 没有被遮蔽,因此优化范围链遍历。
  • @user2612030: void 0 是一个表达式(使用void 运算符),它返回原始undefined,就像SterlingArcher 写的那样。
  • @Pointy,你错了:先点,void 关键字在其自身之后运行表达式,所以 for 做了一些事情:每次迭代运行 0!第二点,我尝试了相同的代码,但在 DOM 中创建和删除元素,以便为每次迭代做更多的事情。这是fiddle

标签: javascript performance


【解决方案1】:

其实我才意识到void 0undefined的区别。 undefined 是全局范围的值,void 是运算符。此测试中发生的情况是全局检查未定义,而 void 0,因为它是使用运算符 void 的表达式,不需要范围遍历来检查其值。如果您将undefined 传递给IIFE 包装器,则测试结果将是相同的。原始测试中显示的性能差异实际上仅测量了 1e6 次范围遍历的时间成本。

进一步的代码证明是这种情况。下面的 for 循环具有相同的执行时间:

(function(start, x, z, undefined, c, Math){
    for (var i=0; i<z; i++){
    if (x !== undefined){
        c = Math.random();
    }
    }
    console.info('t1 ', Date.now() - start);
    start = Date.now();
    c = 0;
    for (var i=0; i<z; i++){
        if (x !== void 0){
            c = Math.random();
        }
    }
    console.info('t1 ', Date.now() - start);
})(Date.now(), '', 1e6, undefined, 0, Math)

rock star 确实指出结果取决于代码的编写方式,例如是否访问内存中的条件分配值。根据我的测试,如果您获取值并将其作为参数传递给函数,它将有很大的不同。那时浏览器可能会决定做更少的优化。尽管如此,在我运行的每个测试中,void 0 仍然比undefined 更快或等效,使用更少的 kb,并且消除了对遍历范围的担忧。

【讨论】:

  • “原始测试中显示的性能差异实际上只测量了 1e6 次范围遍历的时间成本。” 循环本身呢?如何进行优化?它需要多少次通过,以什么顺序?也许使用void 0,他们的优化让他们足够早地消除if 语句以消除整个循环,但是使用undefinedif 被消除,但在稍后的传递中,循环本身仍然存在。或者,undefined if 可能会保留,但范围遍历会被消除,因此循环和 === 比较仍然存在。
  • 它在任何意义上都没有优化循环。您可以在if 块内粘贴任何您想要的内容,或者根据您的需要评估void 0undefined。结果是一样的。此外,将 undefined 注入 IIFE 使得结果完全相同,证明 if 循环并没有被浏览器偷偷优化。
  • 为什么在if 块中放一些东西会改变什么? if 总是false,所以里面的代码永远不会运行。并且声明循环在任何意义上都没有优化是非常愚蠢的。您不知道正在发生哪些优化以及它们可能在什么条件下发生。除非你要告诉我你已经研究过你正在测试的实现的源代码?
  • “证明 if 循环没有被浏览器秘密优化” 不,你没有仔细阅读我关于多次优化传递的可能性的评论,并且当它们可能相互关联时发生。也许与全局变量相关的任何优化都发生在最后,以便它们可以保证它们不会被更改或隐藏。面对现代优化编译器的巨大复杂性,您的假设太多了。
  • 再次阅读我的评论。我说评估 void 0 和 undefined 但是你想要。
猜你喜欢
  • 1970-01-01
  • 2015-07-08
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
相关资源
最近更新 更多