Search code examples
javascriptevaljsperf

eval() is slowing down other code, why?


Using eval anywhere in a program appears to slow down other code even when never executed. Why is this?

In the below example there is the code:

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;
  }
}

If eval() is commented out both simpleFor() and using a for loop have comparable performance. When eval() is there the native loop is gets an ~85% slowdown. I have tested with Chrome/Firefox from jsperf and, using a similar script, nodejs.

Example is at: http://jsperf.com/eval-wierdness

My original idea, and how I found this, was to create a function to create performance efficient mapping functions like:

// 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);
}

Is it possible to make such a function efficient while not slowing down other code?


Solution

  • You can do this by 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);
    }
    

    Generally speaking, eval breaks many compiler optimizations. Specifically in this code fragment, it slows down other code because it can take both global and local scopes into the evaluated code. It breaks some optimization JIT compiler can do because variables in the loop must be tracked for the sake of eval. But in simpleFor engine does not need to care about variables(so the function can be readily cached or so).

    It's hard to say Function construct is better than eval in the sense of security, but Function does not take local scope into account, so it might be faster.

    I have a reference micro benchmark here to illustrate the performance difference between these two. http://jsperf.com/eval-vs-func-so-question