为什么封装的Javascript函数有如此巨大的性能差异

Why this huge performance difference for an encapsulated Javascript function?

本文关键字:巨大 性能 封装 Javascript 函数 为什么      更新时间:2024-02-05

所以我有一个简单的代码:

function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }
  return inside;
}
var start = Date.now();
Run();
console.log(Date.now() - start);

它将在335ms左右输出一段时间。真不错。但是,如果我这样封装Run函数:

var d = Date.now();
(function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }
  return inside;
})();
console.log(Date.now() - d);

它将输出18319ms,这比以前的情况差得多。为什么会这样?

此外,如果重要的话,我在控制台的Chrome 26.0.1410.63上运行它。在node.js上,这两个代码段在控制台上都表现良好。

函数分离和函数表达式WRT对优化没有区别,这太荒谬了。


Google Chrome中的控制台代码封装在with语句中,如下所示:

 with ((console && console._commandLineAPI) || {}) {
      //Your code is concatenated here
 }

因为函数声明是挂起的,所以前一个代码实际上是这样的:

function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }
  return inside;
}
with ((console && console._commandLineAPI) || {}) {
  var start = Date.now();
  Run();
  console.log(Date.now() - start);
}

因此,声明在with语句外运行。事实上,在块中有函数声明是无效的语法,函数声明只能是顶级语句。

因此,无论如何,由于历史原因,V8很好,并将其提升,而不是抛出语法错误:

var i = 3;
with({i:4}) {
    function test() {
        console.log(i);
    }
}
test();//logs 3 so it is obviously **not** under `with` influence

因此,因为声明不在with语句下,所以它将运行得更快。With语句在V8下是不可优化的,它还破坏了词法范围。


*不可优化意味着优化编译器不会查看代码,而只有通用编译器会为函数生成代码。它与firefox的解释器与JIT模式相当。如果您想了解更多关于V8中哪些语言功能禁用优化的信息,请阅读优化杀手