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

时间:2014-11-07 13:19:12

标签: javascript eval jsperf

在程序中的任何地方使用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的Chrome / Firefox进行了测试,并使用类似的脚本nodejs。

示例位于: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);
}

是否可以在不降低其他代码速度的同时提高效率?

2 个答案:

答案 0 :(得分:3)

您可以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

答案 1 :(得分:0)

大多数现代JavaScript引擎都不直接评估代码。他们将代码编译成一些中间形式,优化它,然后执行它。

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