eval()正在减慢其他代码的速度,为什么



在程序中的任何位置使用eval都会减慢其他代码的速度,即使从未执行过为什么

在下面的例子中有代码:

var data = Array.apply(null, Array(10000)).map(function(_, i) {
  return i;
});
function notCalled() {
  eval();
}
function simpleFor (d){
  for (var i = 0, len = d.length; i < len; i += 1) {
    d[i] = d[i] + 1;
  }
}

如果eval()被注释掉,则simpleFor()和使用for循环都具有可比较的性能。当eval()在那里时,本机循环会减慢约85%。我已经从jsperf和nodejs使用Chrome/Firefox进行了测试,并使用了类似的脚本。

示例位于:http://jsperf.com/eval-wierdness

我最初的想法,以及我是如何发现这一点的,是创建一个函数来创建性能高效的映射函数,比如:

// naive first implementation
var emapcache = {};
function emap(fs, list) {
  var f = emapcache[fs];
  if (!f) {
    f = emapcache[fs] = eval('(function (data) { for (var i = 0, s = data.length; i < s; i++) { data[i] = ' + fs.replace(/x/g, '(data[i])') + ';}})');
  }
  return f(list);
}

是否可以在不降低其他代码速度的情况下使这样的函数高效

您可以通过new Function('param', 'body') 完成此操作

var emapcache = {};
function emap(fs, list) {
  var f = emapcache[fs];
  if (!f) {
    f = emapcache[fs] = new Function('data', 'for (var i = 0, s = data.length; i < s; i++) { data[i] = ' + fs.replace(/x/g, '(data[i])') + ';}');
  }
  return f(list);
}

一般来说,eval破坏了许多编译器优化。特别是在这个代码片段中,它减慢了其他代码的速度,因为它可以将全局和局部作用域都带入评估的代码中。它破坏了JIT编译器可以做的一些优化,因为为了eval,必须跟踪循环中的变量。但在simpleFor中,引擎不需要关心变量(因此函数可以很容易地缓存)。

很难说Function结构在安全性方面比eval更好,但Function没有考虑本地范围,所以它可能更快。

我在这里有一个参考微观基准来说明这两者之间的性能差异。http://jsperf.com/eval-vs-func-so-question

大多数现代javascript引擎不直接评估代码。相反,他们将代码编译成某种中间形式,对其进行优化,然后执行它

但是,当您使用eval()时,当脚本被预编译时,程序的整个代码是不可用的。这意味着许多优化根本不可能实现。

相关内容

  • 没有找到相关文章

最新更新