Skip to content

Instantly share code, notes, and snippets.

@Rich-Harris
Created April 5, 2015 23:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rich-Harris/f3d63e4ef4d6680d3052 to your computer and use it in GitHub Desktop.
Save Rich-Harris/f3d63e4ef4d6680d3052 to your computer and use it in GitHub Desktop.
evaluation speed test

A few quick tests to see how much speed you lose by evaluating pre-parsed statements, rather than generating a function with new Function(...) to do it for you. Follows this discussion.

Open a new tab to about:blank, open the console, copy and paste test.js. The results I get:

inline statement: 1.847ms
normal function: 1.852ms
generated function: 1.707ms
naive evaluation: 35.201ms
primed evaluation: 8.932ms

Interestingly, a generated function is just as fast as an inline statement. (I tried including eval in this test, but it's so shockingly slow that I had to close the tab. We're talking 2-3 orders of magnitude slower.) Evaluating code yourself is ~4.5x slower - given that we're still talking about >100m/sec for the example at hand, it's unlikely to be a bottleneck in any real-world apps, but we certainly don't gain any performance (though we do gain CSP compliance and the ability to thwart certain attacks).

var iterations = 1000;
function testInlineStatement ( i ) {
var c;
console.time( 'inline statement' );
while ( i-- ) {
c = 1 + 2;
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'inline statement' );
}
/*function testEvaledStatement ( i ) {
var c;
console.time( 'evaled statement' );
while ( i-- ) {
c = eval( '1 + 2' );
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'evaled statement' );
}*/
function testNormalFunction ( i ) {
function add ( a, b ) {
return a + b;
}
var c;
console.time( 'normal function' );
while ( i-- ) {
c = add( 1, 2 );
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'normal function' );
}
function testGeneratedFunction ( i ) {
var generatedAdd = new Function ( 'a', 'b', 'return a + b;' );
var c;
console.time( 'generated function' );
while ( i-- ) {
c = generatedAdd( 1, 2 );
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'generated function' );
}
function testEvaluation ( i ) {
var one = { t: 1, v: 1 };
var two = { t: 1, v: 2 };
var statement = {
t: 2,
o: [ one, two ]
};
var evaluators = {
1: function ( node ) {
return node.v;
},
2: function ( node ) {
return evaluate( node.o[0] ) + evaluate( node.o[1] );
}
};
function evaluate ( node ) {
return evaluators[ node.t ]( node );
}
var c;
console.time( 'naive evaluation' );
while ( i-- ) {
c = evaluate( statement );
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'naive evaluation' );
}
function testPrimedEvaluation ( i ) {
var one = { t: 1, v: 1 };
var two = { t: 1, v: 2 };
var statement = {
t: 2,
o: [ one, two ]
};
var evaluators = {
1: function ( node ) {
return function () {
return node.v;
};
},
2: function ( node ) {
var lhsEvaluator;
var rhsEvaluator;
lhsEvaluator = getEvaluator( node.o[0] );
rhsEvaluator = getEvaluator( node.o[1] );
return function () {
return lhsEvaluator() + rhsEvaluator();
};
}
};
function getEvaluator ( node ) {
return evaluators[ node.t ]( node );
}
var c;
console.time( 'primed evaluation' );
var evaluator = getEvaluator( statement );
while ( i-- ) {
c = evaluator();
}
console.assert( c === 3, 'c should equal 3' );
console.timeEnd( 'primed evaluation' );
}
testInlineStatement( iterations );
// testEvaledStatement( iterations );
testNormalFunction( iterations );
testGeneratedFunction( iterations );
testEvaluation( iterations );
testPrimedEvaluation( iterations );
@martypdx
Copy link

The generated function running faster is indeed strange.

However, if we change the test to include the time to create the function:

function testNormalFunction ( i ) {

    console.time( 'normal function' );
    var add = function ( a, b ) {
        return a + b;
    };
    var c;
    while ( i-- ) {
        c = add( 1, 2 );
    }
    console.assert( c === 3, 'c should equal 3' );
    console.timeEnd( 'normal function' );
}

function testGeneratedFunction ( i ) {

    console.time( 'generated function' );
    var generatedAdd = new Function ( 'a', 'b', 'return a + b;' );
    var c;
    while ( i-- ) {
        c = generatedAdd( 1, 2 );
    }
    console.assert( c === 3, 'c should equal 3' );
    console.timeEnd( 'generated function' );
}

normal functions win hands down:

inline statement: 0.055ms
generated function: 0.225ms
normal function: 0.150ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment