解析时用到的方法一般是eval或者new function,而目前IE8和Firefox3.1又内置了原生的JSON对象(据说会有一定的性能提升)。那我们在实际使用的时候怎样从这三种方法(因为性能问题,不考虑用javascript实现的解析)里面来选择呢?面对众多的浏览器,哪种方式的性能是最好的呢?
一、测试方法
1、首先指定测试次数及JSON字符串
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
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的性能基本一致
如果有不同意见欢迎拍砖:)
Update:
2009.03.23:屏蔽所有Firefox的Add-Ons再进行测试
由于Known在Firefox下运行代码得到了完全不一致的结果,怀疑是Firefox的插件导致,于是禁掉所有插件后(后来表明几乎由Firebug导致),重新在Firefox2、3下测试了一下,结果如下:
这表明Firefox本身的性能并不是象我们先前测试的那样低,在去掉插件后性能还是很不错。但是没有Firebug一类的插件支持,Firefox对我们的吸引力也大大降低了。
2009.03.31:循环中每次使用新的json字符串
根据Oliver的描述,他猜测是由于Safari4和Chrome缓存了eval的结果从而导致它们的测试成绩“虚”高,测试结果证明了他的推测:
从这个结果中我们可以看到,Opera的性能最好,Ie8其次。
主要修改的代码:
//eval 2: var beginTime = new Date();
for ( i = 0; i < 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 < 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 < 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 < 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 PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<头>
>
解析 JsonString 头>
<身体>
//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;
}
// 现代 WebKit 浏览器至少是 X 级
m = ua.match(/AppleWebKit/([^s]*)/);
if (m&&m[1]) {
o.webkit=parseFloat(m[1]);
}
if (!o.webkit) { // 不是 webkit
// @todo 检查 Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
m=ua.match(/Opera[s/]([^s]*)/);
if (m&&m[1]) {
o.opera=parseFloat(m[1]);
} else { // 不是 opera 或 webkit
m=ua.match(/MSIEs([^;]*)/);
if (m&&m[1]) {
o.ie=parseFloat(m[1]);
} else { // 不是 opera、webkit 或 ie
m=ua.match(/Gecko/([^s]*)/);
if (m) {
o.gecko=1; // 检测到 Gecko,查找修订版
m=ua.match(/rv:([^s)]*)/);
if (m&&m[1]) {
o.gecko=parseFloat(m[1]);
}
}
}
}
}
返回 o;
}();
var Console = {
consoleRegion: null,
getRegion: function() {
if ( this.consoleRegion === null ) {
this.consoleRegion = document.getElementById( "consoleRegion ”);
}
返回 this.consoleRegion;
},
输出: function( text ) {
this.getRegion().innerHTML = "
" 文本;
}
};
//测试代码
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 < count; i ) {
o = eval( "(" jsonString ")" );
}
Console.output( "eval:" ( new Date() - beginTime ) );
//新函数
beginTime = new Date();
for ( i = 0; i < count; i ) {
o = new Function( "return " jsonString )();
}
Console.output( "新函数:" ( new Date() - beginTime ) );
//原生
if ( typeof JSON !== "undefined" ) {
beginTime = new Date();
for ( i = 0; i < count; i ) {
o = JSON.parse( jsonString );
}
Console.output( "native:" ( new Date() - beginTime ) );
} else {
Console.output( "native:不支持!" );
}
//包装器
var __json = null;
if ( typeof JSON !== "undefined" ) {
__json = JSON;
}
var 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 < count; i ) {
o = JSON.parse( jsonString );
}
Console.output( "wrapper:" ( new Date() - beginTime ) );
//alert( o.value.items[0].z );
脚本>
身体>