JavaScript 解析Json字符串的性能比较分析代码

解析时用到的方法一般是eval或者new function,而目前IE8和Firefox3.1又内置了原生的JSON对象(据说会有一定的性能提升)。那我们在实际使用的时候怎样从这三种方法(因为性能问题,不考虑用javascript实现的解析)里面来选择呢?面对众多的浏览器,哪种方式的性能是最好的呢? 一、测试方法 1、首先指定测试次数及JSON字符串
var count = 10000, o = null, i = 0;
var 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}';
2、循环解析并记录时间 eval
var beginTime = new Date(); 
for ( i = 0; i < count; i++ ) { 
    o = eval( "(" + jsonString + ")" ); 
} 
Console.output( "eval:" + ( new Date() - beginTime ) );
new Function
var beginTime = new Date(); 
for ( i = 0; i < count; i++ ) { 
    o = new Function( "return " + jsonString )(); 
} 
Console.output( "new Function:" + ( new Date() - beginTime ) );
native
if ( typeof JSON !== "undefined" ) { 
var beginTime = new Date(); 
for ( i = 0; i < count; i++ ) { 
o = JSON.parse( jsonString ); 
} 
    Console.output( "native:" + ( new Date() - beginTime ) ); 
} else { 
    Console.output( "native:not support!" ); 
}
二、测试对象 选择目前主流的浏览器(不考虑Maxthon一类的外壳),包括IE6、7、8,Firefox2、3、3.1,Chrome,Opera及Safari3、4。 三、测试环境 T9300 CPU + 4G RAM + Windows2003,其中IE8使用的是Vista的环境,IE7在另外一台工作机(2G CPU + 2G RAM + Windows2003),考虑到主要是测试浏览器客户端的性能,结果的误差应该能够接受。 四、测试结果 *数值越小越好 *在当前列中绿色背景的表示性能最好,红色性能最差 1、Firefox2、3全部垫底,IE6的性能优于IE7(可能和机器不一致有关),Chrome和Safari4的性能远远超出其它浏览器。 2、不同的浏览器下eval和new Function的性能不一致,总的来说eval更好,但Firefox下new Function的性能是eval的一倍,为了更好的兼容各个浏览器,我们把对JSON的解析单独封装成一个对象来处理: wrapper
var __json = null; 
if ( typeof JSON !== "undefined" ) { 
    __json = JSON; 
} 
var browser = Browser; 
var JSON = { 
parse: function( text ) { 
  if ( __json !== null ) { 
      return __json.parse( text ); 
  } 
  if ( browser.gecko ) { 
      return new Function( "return " + text )(); 
  } 
      return eval( "(" + text + ")" ) 
} 
}; 
var beginTime = new Date(); 
for ( i = 0; i < count; i++ ) { 
    o = JSON.parse( jsonString ); 
} 
Console.output( "wrapper:" + ( new Date() - beginTime ) );

加入Wrapper后的结果: 由于涉及到调用对象的开销,封装后JSON对象会比单独调用更慢,但它能保证在各个浏览器下使用最适合的方法。

五、结论
解析Json字符串时,不同的浏览器选择不同的方法:
IE6、7使用eval
IE8使用原生的JSON对象
Firefox2、3使用new Function
Safari4使用eval
其它浏览器下eval和new Function的性能基本一致
  

根据Oliver的描述,他猜测是由于Safari4和Chrome缓存了eval的结果从而导致它们的测试成绩“虚”高,测试结果证明了他的推测: 从这个结果中我们可以看到,Opera的性能最好,Ie8其次。 主要修改的代码:

var beginTime = new Date(); 
  for (i = 0; i & lt; count; i++ ) {
    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}' + ")");
  }
  Console.output("eval:" + (new Date() - beginTime));
  //new Function 
  beginTime = new Date();
  for (i = 0; i & lt; count; i++ ) {
    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}')();
  }
  Console.output("new Function:" + (new Date() - beginTime));
  //native 
  if (typeof JSON !== "undefined") {
    beginTime = new Date();
    for (i = 0; i & lt; count; i++ ) {
      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}');
    }
    Console.output("native:" + (new Date() - beginTime));
  } else {
    Console.output("native:not support!");
  }
  //wrapper 
  var __json = null;
  if (typeof JSON !== "undefined") {
    __json = JSON;
  }
  var browser = Browser;
  var JSON = {
    parse: function (text) {
      if (__json !== null) {
        return __json.parse(text);
      }
      if (browser.gecko) {
        return new Function("return " + text)();
      }
      return eval("(" + text + ")")
    }
  };
  beginTime = new Date();
  for (i = 0; i & lt; count; i++ ) {
    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}');
  }
  Console.output("wrapper:" + (new Date() - beginTime));

附:全部代码

<!DOCTYPE HTML> 
  <html> 
  <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>Parse JsonString</title> 
  </head> 
  <body> 
  <div id="consoleRegion"></div> 
  <script type="text/javascript"> 
  //yui 
  var Browser = function () {
    var o = {
      ie: 0,
      opera: 0,
      gecko: 0,
      webkit: 0
    };
    var ua = navigator.userAgent, m;
    if ((/KHTML/).test(ua)) {
      o.webkit = 1;
    }
    // Modern WebKit browsers are at least X-Grade 
    m = ua.match(/AppleWebKit\/([^\s]*)/);
    if (m & amp;& amp; m[1]) {
      o.webkit = parseFloat(m[1]);
    }
    if (!o.webkit) { // not webkit 
      //@todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) 
      m = ua.match(/Opera[\s\/]([^\s]*)/);
      if (m & amp;& amp; m[1]) {
        o.opera = parseFloat(m[1]);
      } else { // not opera or webkit 
        m = ua.match(/MSIE\s([^;]*)/);
        if (m & amp;& amp; m[1]) {
          o.ie = parseFloat(m[1]);
        } else { // not opera, webkit, or ie 
          m = ua.match(/Gecko\/([^\s]*)/);
          if (m) {
            o.gecko = 1; // Gecko detected, look for revision 
            m = ua.match(/rv:([^\s\)]*)/);
            if (m & amp;& amp; m[1]) {
              o.gecko = parseFloat(m[1]);
            }
          }
        }
      }
    }
    return o;
  }();
  var Console = {
    consoleRegion: null,
    getRegion: function () {
      if (this.consoleRegion === null) {
        this.consoleRegion = document.getElementById("consoleRegion");
      }
      return this.consoleRegion;
    },
    output: function (text) {
      this.getRegion().innerHTML += "<br/>" + text;
    }
  };
  //test code 
  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}';
  //eval 
  var beginTime = new Date();
  for (i = 0; i & lt; count; i++ ) {
    o = eval("(" + jsonString + ")");
  }
  Console.output("eval:" + (new Date() - beginTime));
  //new Function 
  beginTime = new Date();
  for (i = 0; i & lt; count; i++ ) {
    o = new Function("return " + jsonString)();
  }
  Console.output("new Function:" + (new Date() - beginTime));
  //native 
  if (typeof JSON !== "undefined") {
    beginTime = new Date();
    for (i = 0; i & lt; count; i++ ) {
      o = JSON.parse(jsonString);
    }
    Console.output("native:" + (new Date() - beginTime));
  } else {
    Console.output("native:not support!");
  }
  //wrapper 
  var __json = null;
  if (typeof JSON !== "undefined") {
    __json = JSON;
  }
  var browser = Browser;
  var JSON = {
    parse: function (text) {
      if (__json !== null) {
        return __json.parse(text);
      }
      if (browser.gecko) {
        return new Function("return " + text)();
      }
      return eval("(" + text + ")")
    }
  };
  beginTime = new Date();
  for (i = 0; i & lt; count; i++ ) {
    o = JSON.parse(jsonString);
  }
  Console.output("wrapper:" + (new Date() - beginTime));
//alert( o.value.items[0].z );
  </script> 
  </body> 
  </html>