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

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

一、测试方法

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

   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 < 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: }

二、测试对象

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

 

四、测试结果

image

*数值越小越好

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

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 < count; i++ ) {
  19:     o = JSON.parse( jsonString ); }
  20: Console.output( "wrapper:" + ( new Date() - beginTime ) );

加入Wrapper后的结果:

image

由于涉及到调用对象的开销,封装后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下测试了一下,结果如下:

image 

这表明Firefox本身的性能并不是象我们先前测试的那样低,在去掉插件后性能还是很不错。但是没有Firebug一类的插件支持,Firefox对我们的吸引力也大大降低了。

 

  • 2009.03.31:循环中每次使用新的json字符串

根据Oliver的描述,他猜测是由于Safari4和Chrome缓存了eval的结果从而导致它们的测试成绩“虚”高,测试结果证明了他的推测:

image

从这个结果中我们可以看到,Opera的性能最好,Ie8其次。

主要修改的代码:

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

 

附:全部代码

 

ContractedBlock.gif ExpandedBlockStart.gif Code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<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&&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&&m[1]) {
                        o.opera
=parseFloat(m[1]);
                    }
else { // not opera or webkit
                        m=ua.match(/MSIE\s([^;]*)/);
                       
if (m&&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&&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 < count; i++ ) {
                o
= eval( "(" + jsonString + ")" );
            }
            Console.output(
"eval:" + ( new Date() - beginTime ) );
           
//new Function
            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" ) {
                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!" );
            }
           
//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( jsonString );

            }
            Console.output(
"wrapper:" + ( new Date() - beginTime ) );
           
//alert( o.value.items[0].z );
        </script>
   
</body>
</html>

转载于:https://www.cnblogs.com/gOODiDEA/archive/2009/03/22/1419071.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值