Search code examples
javascriptperformanceoptimizationv8

Why this huge performance difference for an encapsulated Javascript function?


So I have this simple code:

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

And it will output some time around 335ms. That's pretty good. But, if I encapsulate the Run function like this:

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

It will output 18319ms, which is much worse than the case before. Why is this ?

Also, if it matters, I'm running it on Chrome 26.0.1410.63, in the console. On node.js both snippets perform well on the console.


Solution

  • There is no difference with function decleration and function expressions WRT to optimization, that would be ridiculous.


    Console code in Google Chrome is wrapped in with statement like this:

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

    Because function declarations are hoisted, the former code will be effectively this:

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

    So the declaration is running outside with statement. In fact it is not valid syntax to have function declaration in a block, function declaration can only be a top level statement.

    So anyway because of historical reasons V8 is nice and hoists it out instead of throwing syntax error:

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

    So because the declaration is not under with statement, it will run much faster. With statement is not optimizable* under V8 and also breaks lexical scoping.


    *Not optimizable means the optimizing compiler will not look at the code instead only the generic compiler will generate code for the function. It is comparable to firefox's interpreter vs JIT mode. If you wish to know more about what language features disable optimization in V8, read optimization killers