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

2021年1月15日   |   by tgcode

我们在使用AJAX来做服务器端和客户端交互的时候,一般的做法是让服务器端返回一段JSON字符串,然后在客户端把它解析成JavaScript对象。解析时用到的方法一般是eval或者new function,而目前IE8和Firefox3.1又内置了原生的JSON对象(据说会有一定的性能提升)。那我们在实际使用的时候怎样从这三种方法(因为性能问题,不考虑用javascript实现的解析)里面来选择呢?面对众多的浏览器,哪种方式的性能是最好的呢?

一、测试方法

1、首先指定测试次数及JSON字tgcode符串

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

2、循环解析并记录时间

  • eval
   1: var beginTime = new Date();

   2: for ( i = 0; 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 

   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 

   4:         o = JSON.parse( jsonString );     }

   5:     Console.output( "native:" + ( new Date() - beginTime ) );

   6: } else {

   7:     Console.output( "native:not support!" );

   8: }

二、测试对象

选择目前主流的浏览器(不考虑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),考虑到主要是测试浏览器客户端的性能,结果的误差应该能够接受。

四、测试结果

%title插图%num

*数值越小越好

*在当前列中绿色背景的表示性能最好,红色性能最差

1、Firefox2、3全部垫底,IE6的性能优于IE7(可能和机器不一致有关),Chrome和Safari4的性能远远超出其它浏览器。

2、不同的浏览器下eval和new Function的性能不一致,总的来说eval更好,但Firefox下new Function的性能是eval的一倍,为了更好的兼容各个浏览器,我们把对JSON的解析单独封装成一个对象来处理:

  • 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 

  19:     o = JSON.parse( jsonString ); }

  20: Console.output( "wrapper:" + ( new Date() - beginTime ) );

加入Wrapper后的结果:

%title插图%num

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

五、结论

解析Json字符串时,不同的浏览器选择不同的方法:

  • IE6、7使用eval
  • IE8使用原生的JSON对象
  • Firefox2、3使用new Function
  • Safari4使用eval
  • 其它浏览器下eval和new Function的性能基本一致

如果有不同意见欢迎拍砖:)

附:全部代码

%title插图%num%title插图%numCode
<!–

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

–><!–DOCTYPEHTMLPUBLIC”-//W3C//DTDHTML4.01//EN””http://www.w3.org/TR/html4/strict.dtd”>
html>
head>
metahttp-equiv=”Content-Type”content=”text/html;charset=utf-8″/>
title>ParseJsonString<!–title>
<!–head>
body>
divid=”consoleRegion”><!–div>
scripttype=”text/javascript”>
//yui
varBrowser=function(){
varo={
ie:
0,
opera:
0,
gecko:
0,
webkit:
0
};
varua=navigator.userAgent,m;
if((/KHTML/).test(ua)){
o.webkit
=1;
}
//ModernWebKitbrowsersareatleastX-Grade
m=ua.match(/AppleWebKit/([^s]*)/);
if(m&&m[1]){
o.webkit
=parseFloat(m[1]);
}

if(!o.webkit){//notwebkit
//@todocheckOpera/8.01(J2ME/MIDP;OperaMini/2.0.4509/1316;fi;U;ssr)
m=ua.match(/Opera[s/]([^s]*)/);
if(m&&m[1]){
o.opera
=parseFloat(m[1]);
}
else{//notoperaorwebkit
m=ua.match(/MSIEs([^;]*)/);
if(m&&m[1]){
o.ie
=parseFloat(m[1]);
}
else{//notopera,webkit,orie
m=ua.match(/Gecko/([^s]*)/);
if(m){
o.gecko
=1;//Geckodetected,lookforrevision
m=ua.match(/rv:([^s)]*)/);
if(tgcodem&&m[1]){
o.gecko
=parseFloat(m[1]);
}
}
}
}
}
returno;
}();

varConsole={
consoleRegion:
null,

getRegion:function(){
if(this.consoleRegion===null){
this.consoleRegion=document.getElementById(consoleRegion);
}
returnthis.consoleRegion;
},

output:function(text){

this.getRegion().innerHTML+=
+text;

}
};
//testcode
varcount=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
varbeginTime=newDate();
for(i=0;icotgcodeunt;i++){
o
=eval((+jsonString+));
}
Console.output(
eval:+(newDate()beginTime));
//newFunction
beginTime=newDate();
for(i=0;icount;i++){
o
=newFunction(return+jsonString)();
}
Console.output(
newFunction:+(newDate()beginTime));
//native
if(typeofJSON!==undefined){
beginTime
=newDate();
for(i=0;icount;i++){
o
=JSON.parse(jsonString);

}
Console.output(native:+(newDate()beginTime));
}
else{
Console.output(
native:notsupport!);
}
//wrapper
var__json=null;
if(typeofJSON!==undefined){
__json
=JSON;
}
varbrowser=Browser;
varJSON={
parse:
function(text){
if(__json!==null){
return__json.parse(text);
}
if(browser.gecko){
returnnewFunction(return+text)();
}
returneval((+text+))
}
};
beginTime
=newDate();
for(i=0;icount;i++){
o
=JSON.parse(jsonString);

}
Console.output(wrapper:+(newDate()beginTime));
//alert(o.value.items[0].z);
<!–script>
<!–body>
<!–html>