JSON Performance comparison of eval, new Function and JSON

We parse a JSON string to JSON object when we handle response of server in AJAX.We use eval or new Function to parse JSON string normally, and IE8 and Firefox3.1 has a native JSON support( Native JSON parsing is much faster).How can we choose from the three methods in practice? And how can we know whose performance is the best since there are so many browers?

Code & Concern

defined a json string and circle numbers

   1: var count = 10000, o = null, i = 0, jsonString = '{"value":{"items": [{"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}';
parse json string and record time
  • eval
   1: var beginTime = new Date();
   2: for ( i = 0; i < count; i++ ) {
   3:     o = eval( "(" + jsonString + ")" );
   4: }
   5: Console.output( "eval:" + ( new Date() - beginTime ) );
  • new Function
   1: var beginTime = new Date();
   2: for ( i = 0; i < count; i++ ) {
   3:     o = new Function( "return " + jsonString )();
   4: }
   5: Console.output( "new Function:" + ( new Date() - beginTime ) );
  • native
   1: if ( typeof JSON !== "undefined" ) {
   2:     var beginTime = new Date();
   3:     for ( i = 0; i < count; i++ ) {
   4:         o = JSON.parse( jsonString );     }
   5:     Console.output( "native:" + ( new Date() - beginTime ) );
   6: } else {
   7:     Console.output( "native:not support!" );
   8: }

Browsers

It includes IE6, 7 , 8; Firefox2, 3, 3.1; Chrome; Opera and Safari3, 4.

 

Environment

T9300 CPU + 4G RAM + Windows2003, IE8 in Vista, IE7 in another machine( 2G CPU + 2G RAM + Windows2003 )

 

Result

image

*The smaller the number is,the better the result will be.

*The column in green shows the best performance, while in red shows the worst.

Firefox2, 3 gain the worst performance, IE6 better than IE7( may be related with machines ), Chrome and Safari4 are far superior to other browsers.

Genally speaking, eval is better than new Function,though they have different results in different browsers. But the "new Function" is the double performance of eval in Firefox, so we wrap a class to parse json string to gain better performance in cross-browser.

  • wrapper
   1: var __json = null;
   2: if ( typeof JSON !== "undefined" ) {
   3:     __json = JSON;
   4: }
   5: var browser = Browser;
   6: var JSON = {
   7:     parse: function( text ) {
   8:         if ( __json !== null ) {
   9:             return __json.parse( text );
  10:         }
  11:         if ( browser.gecko ) {
  12:             return new Function( "return " + text )();
  13:         }
  14:         return eval( "(" + text + ")" )
  15:     }
  16: };          
  17: var beginTime = new Date();
  18: for ( i = 0; i < count; i++ ) {
  19:     o = JSON.parse( jsonString ); }
  20: Console.output( "wrapper:" + ( new Date() - beginTime ) );

The results with wrapper:

image

After wrapping, it is slower than before due to the cost, but it offers a guarantee to call better implementation.

 

Conclusion

We should choose a different method when using different browsers:

  • choose eval in IE6, 7 
  • choose native JSON in IE8 
  • choose new Function in Firefox2, 3 
  • choose eval in Safari4 
  • eval has the same performance as new Function on the whole when you use the other browsers.

 

Hope this helps,

Andy

 

Update:

  • 2009.03.23: Disabled all Firefox' Add-Ons 

someone told me got a different result after he ran the code in Firefox, I doubt Firefox’s Add-Ons conduces to wrong result, so I run it after I disabled Firebug.

image

We made a mistake in tests about Firefox, but it is not good enough to our without Firebug.

 

  • 2009.03.31: Use different Json strings in the loops

according to Oliver' reply, modify code:

   1: for ( i = 0; i < count; i++ ) {
   2:     o = eval("(" + '{"value":{"items": [{"x":' + i + ',"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}' + ")");
   3: }

result:

image

opera is best performance, but Ie8 is better than chrome and safari.

main code:

   1: //test code
   2: var count = 10000, o = null, i = 0, jsonString = "";
   3:  
   4: //eval
   5: var beginTime = new Date();
   6: for ( i = 0; i < count; i++ ) {
   7:     o = eval("(" + '{"value":{"items": [{"x":' + i + ',"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}' + ")");
   8: }
   9: Console.output( "eval:" + ( new Date() - beginTime ) );
  10: //new Function
  11: beginTime = new Date();
  12: for ( i = 0; i < count; i++ ) {
  13:     o = new Function("return " + '{"value":{"items": [{"x":' + i + ',"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}')();
  14: }
  15: Console.output( "new Function:" + ( new Date() - beginTime ) );
  16: //native
  17: if ( typeof JSON !== "undefined" ) {
  18:     beginTime = new Date();
  19:     for ( i = 0; i < count; i++ ) {
  20:         o = JSON.parse('{"value":{"items": [{"x":' + i + ',"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}');
  21:     }
  22:     Console.output( "native:" + ( new Date() - beginTime ) );
  23: } else {
  24:     Console.output( "native:not support!" );
  25: }
  26: //wrapper
  27: var __json = null;
  28: if ( typeof JSON !== "undefined" ) {
  29:     __json = JSON;
  30: }
  31: var browser = Browser;
  32: var JSON = {
  33:     parse: function( text ) {
  34:         if ( __json !== null ) {
  35:             return __json.parse( text );
  36:         }
  37:         if ( browser.gecko ) {
  38:             return new Function( "return " + text )();
  39:         }
  40:         return eval( "(" + text + ")" )
  41:     }
  42: };          
  43: beginTime = new Date();
  44: for ( i = 0; i < count; i++ ) {
  45:     o = JSON.parse('{"value":{"items": [{"x":' + i + ',"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}');
  46: }
  47: Console.output( "wrapper:" + ( new Date() - beginTime ) );

 

Source:

   1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
   2: <html>
   3:     <head>
   4:         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   5:         <title>Parse JsonString</title>
   6:     </head>
   7:     <body>
   8:         <div id="consoleRegion"></div>
   9:         <script type="text/javascript">
  10:             //yui
  11:             var Browser = function() {
  12:                 var o = {
  13:                     ie: 0,
  14:                     opera: 0,
  15:                     gecko: 0,
  16:                     webkit: 0
  17:                 };
  18:                 var ua = navigator.userAgent, m;
  19:                 if ( ( /KHTML/ ).test( ua ) ) {
  20:                     o.webkit = 1;
  21:                 }
  22:                 // Modern WebKit browsers are at least X-Grade
  23:                 m = ua.match(/AppleWebKit\/([^\s]*)/);
  24:                 if (m&&m[1]) {
  25:                     o.webkit=parseFloat(m[1]);
  26:                 }
  27:  
  28:                 if (!o.webkit) { // not webkit
  29:                     // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
  30:                     m=ua.match(/Opera[\s\/]([^\s]*)/);
  31:                     if (m&&m[1]) {
  32:                         o.opera=parseFloat(m[1]);
  33:                     } else { // not opera or webkit
  34:                         m=ua.match(/MSIE\s([^;]*)/);
  35:                         if (m&&m[1]) {
  36:                             o.ie=parseFloat(m[1]);
  37:                         } else { // not opera, webkit, or ie
  38:                             m=ua.match(/Gecko\/([^\s]*)/);
  39:                             if (m) {
  40:                                 o.gecko=1; // Gecko detected, look for revision
  41:                                 m=ua.match(/rv:([^\s\)]*)/);
  42:                                 if (m&&m[1]) {
  43:                                     o.gecko=parseFloat(m[1]);
  44:                                 }
  45:                             }
  46:                         }
  47:                     }
  48:                 }
  49:                 return o;
  50:             }();
  51:  
  52:             var Console = {
  53:                 consoleRegion: null,
  54:  
  55:                 getRegion: function() {
  56:                     if ( this.consoleRegion === null ) {
  57:                         this.consoleRegion = document.getElementById( "consoleRegion" );
  58:                     }
  59:                     return this.consoleRegion;
  60:                 },
  61:  
  62:                 output: function( text ) {                     this.getRegion().innerHTML += "<br/>" + text;                 }
  63:             };
  64:             //test code
  65:             var count = 10000, o = null, i = 0, jsonString = '{"value":{"items": [{"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}';
  66:             //eval
  67:             var beginTime = new Date();
  68:             for ( i = 0; i < count; i++ ) {
  69:                 o = eval( "(" + jsonString + ")" );
  70:             }
  71:             Console.output( "eval:" + ( new Date() - beginTime ) );
  72:             //new Function
  73:             beginTime = new Date();
  74:             for ( i = 0; i < count; i++ ) {
  75:                 o = new Function( "return " + jsonString )();
  76:             }
  77:             Console.output( "new Function:" + ( new Date() - beginTime ) );
  78:             //native
  79:             if ( typeof JSON !== "undefined" ) {
  80:                 beginTime = new Date();
  81:                 for ( i = 0; i < count; i++ ) {
  82:                     o = JSON.parse( jsonString );                 }
  83:                 Console.output( "native:" + ( new Date() - beginTime ) );
  84:             } else {
  85:                 Console.output( "native:not support!" );
  86:             }
  87:             //wrapper
  88:             var __json = null;
  89:             if ( typeof JSON !== "undefined" ) {
  90:                 __json = JSON;
  91:             }
  92:             var browser = Browser;
  93:             var JSON = {
  94:                 parse: function( text ) {
  95:                     if ( __json !== null ) {
  96:                         return __json.parse( text );
  97:                     }
  98:                     if ( browser.gecko ) {
  99:                         return new Function( "return " + text )();
 100:                     }
 101:                     return eval( "(" + text + ")" )
 102:                 }
 103:             };          
 104:             beginTime = new Date();
 105:             for ( i = 0; i < count; i++ ) {
 106:                 o = JSON.parse( jsonString );             }
 107:             Console.output( "wrapper:" + ( new Date() - beginTime ) );
 108:             //alert( o.value.items[0].z );
 109:         </script>
 110:     </body>
 111: </html> 
Published Sunday, March 22, 2009 9:21 AM by gOODiDEA

Comments

# re: JSON Performance comparison of eval, new Function and JSON

Friday, March 27, 2009 7:09 PM by Oliver

The problem with this is that both Nitro (the main webkit js engine) and V8 (the js engine used by chrome) cache eval code -- that's why they are an order of magnitude faster than the other browsers in your test (there are actually sites that loop over eval with a constant string :-/ ); based on the numbers i would guess V8 caches the results of new Function as well -- you may want to try making the loops use different strings for eval/new Function in order to get a more real world measurement of JSON parsing performance -- eg. appending a number (in comments should be sufficient i think) so that you get the true cost of parsing/compilation.

# re: JSON Performance comparison of eval, new Function and JSON

Monday, March 30, 2009 10:11 PM by gOODiDEA

@Oliver:

thanks, you are right.

# re: JSON Performance comparison of eval, new Function and JSON

Wednesday, May 20, 2009 12:30 AM by Johnny

Browsers have different performance for string concatenation, that part should be left out of the timing, that could be interfering with the result. A pre-built array of JSON strings would be better.

# re: JSON Performance comparison of eval, new Function and JSON

Wednesday, September 30, 2009 6:58 PM by Oliver

Safari 4.0.3 and Chrome 3 have native JSON implementations now.

# re: JSON Performance comparison of eval, new Function and JSON

Thursday, August 25, 2011 3:39 PM by Krishan Kumar

i thing new Function() is good....

# re: JSON Performance comparison of eval, new Function and JSON

Wednesday, June 27, 2012 11:12 PM by Redd

I recently got an B&D lst220 battery powered trimmer and after using it, I would not get another

gas powered string trimmer.

# re: JSON Performance comparison of eval, new Function and JSON

Friday, March 8, 2013 3:31 PM by Pratt

This website was... how do I say it? Relevant!!

Finally I have found something that helped me.

Kudos!

# re: JSON Performance comparison of eval, new Function and JSON

Saturday, April 6, 2013 6:24 PM by Branch

Hi, every time i used to check webpage posts here early in the break of day, for the

reason that i love to learn more and more.

# re: JSON Performance comparison of eval, new Function and JSON

Saturday, March 15, 2014 11:21 AM by Aiken

Definitely believe that which you said. Your favorite

justification seemed to be on the net the easiest thing to be aware of.

I say to you, I definitely get irked while people think about

worries that they plainly do not know about. You managed to hit the nail upon the top as well as defined out the whole thing without

having side-effects , people can take a signal.

Will likely be back to get more. Thanks

Leave a Comment

(required) 
(required) 
(optional)
(required)