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> 

9 Comments

  • 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.

  • @Oliver:
    thanks, you are right.

  • 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.

  • Safari 4.0.3 and Chrome 3 have native JSON implementations now.

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

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

  • This website was... how do I say it? Relevant!!
    Finally I have found something that helped me.
    Kudos!

  • 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.

  • 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

Comments have been disabled for this content.