2

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?

AnnanFay
  • 9,573
  • 15
  • 63
  • 86
  • Did you just do this test or did you test the `eval` approach with a your real code and compared the performance? It is not uncommon that an optimizer, like the one you have in current JS engines, will fail to do correct or any optimizations with that specialized type of code, as they are designed to work on real world code. – t.niese Nov 07 '14 at 14:26

2 Answers2

3

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

Herrington Darkholme
  • 5,979
  • 1
  • 27
  • 43
0

Most modern javascript engines do not evaluate code directly. They instead compile the code into some intermediate form, optimize it, and then execute it.

However, when you use eval(), the whole code of the program isn't available when the script is precompiled. That means that many optimizations are simply not possible.

Philipp
  • 67,764
  • 9
  • 118
  • 153
  • I agree that `eval` is at least not good. But the phrasing of this answer seems to magnify the delinquency of `eval` these day. http://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea#comment5086453_86580 – Herrington Darkholme Nov 07 '14 at 13:56