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

本文通过实验对比了不同浏览器环境下使用eval、newFunction及原生JSON对象解析JSON字符串的性能,并提出了一个兼容性强的封装方案。

原文转自:http://www.cnblogs.com/gOODiDEA/archive/2009/03/22/1419071.html

我们在使用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 ) );

 

附:全部代码

 


<!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>

### 回答1: JavaScript可以使用内置的JSON对象来解析JSON字符串JSON对象有两个方法:JSON.parse()和JSON.stringify()。JSON.parse()方法将JSON字符串转换为JavaScript对象,而JSON.stringify()方法将JavaScript对象转换为JSON字符串。例如: var jsonStr = '{"name":"John","age":30,"city":"New York"}'; var jsonObj = JSON.parse(jsonStr); console.log(jsonObj.name); //输出John 在这个例子中,我们首先定义了一个JSON字符串,然后使用JSON.parse()方法将其转换为JavaScript对象。最后,我们访问了对象的name属性并将其输出到控制台。 需要注意的是,JSON字符串必须符合JSON格式,否则解析会失败。例如,如果JSON字符串中有未加引号的属性名或单引号而不是双引号,解析将失败。 ### 回答2: JSON全称是JavaScript Object Notation,是一种轻巧的数据交换格式。JSON中的数据结构类似于JavaScript对象,因此JavaScript可以方便地解析JSON字符串。 在JavaScript中,可以使用eval()函数来解析JSON字符串。eval()函数将一个字符串当作JavaScript代码执行并返回结果。因此,我们可以使用eval()函数将JSON字符串转换为JavaScript对象,从而完成解析。 但是eval()函数存在一些安全问题,因为它会执行输入的任何JavaScript代码。如果JSON字符串来自不受信任的来源,那么可能包含恶意代码,会导致安全漏洞。因此,eval()函数不是解析JSON字符串的最佳方法。 现代浏览器提供了JSON.parse()方法来解析JSON字符串JSON.parse()可以将JSON字符串转换为JavaScript对象,而且对于不合法的JSON格式会抛出异常以及其他一些问题,例如,JSON字符串内部的单引号、指数表示法和特定值(如undefined)可能无法在JSON中表示,需要进行特殊处理。 JSON.parse(str, reviver)函数可以接收一个reviver参数,可以用来转换解析出来的结果。reviver是一个函数,它接收两个参数,一个是属性名,另一个是属性值。当JSON.parse()解析出属性值后,就会调用reviver函数,这样就可以在这个函数内部对这个属性进行处理。 在代码中,如果我们有一个JSON字符串,我们可以使用JSON.parse()来解析它。例如: var jsonString = '{"name": "John", "age": 30, "city": "New York"}'; var jsonObj = JSON.parse(jsonString); console.log(jsonObj.name); // 输出 "John" 解析后的jsonObj就是一个JavaScript对象,我们可以直接访问其中的属性。 总结来说,JavaScript可以使用eval()函数或JSON.parse()方法来解析JSON字符串,但是安全考虑应该优先选择使用JSON.parse()方法。JSON.parse()方法还可以使用reviver参数来对解析出的结果进行转换和处理。 ### 回答3: 在JavaScript中,解析JSON字符串是常见的操作。JSONJavaScript对象表示法的缩写,它是一种轻量级的数据交换格式。它提供了一种简单的方式来描述复杂的数据结构,包括数组和对象。 JavaScript内置了一个解析JSON字符串的函数`JSON.parse()`。此函数可以将JSON字符串转换为JavaScript对象,使开发者能够轻松地操作这些数据。 例如,如果我们有以下JSON字符串: ```javascript var jsonString = '{"name": "Tom", "age": 21, "gender": "male"}'; ``` 我们可以使用`JSON.parse()`来将其解析成一个对象: ```javascript var json = JSON.parse(jsonString); console.log(json.name); //输出 "Tom" console.log(json.age); //输出 21 console.log(json.gender); //输出 "male" ``` 除了从字符串解析JSON外,我们还可以使用`JSON.stringify()`函数将JavaScript对象转换为JSON字符串。例如,如果我们有以下JavaScript对象: ```javascript var obj = { name: "Tom", age: 21, gender: "male" }; ``` 我们可以使用`JSON.stringify()`将其转换为JSON字符串: ```javascript var jsonString = JSON.stringify(obj); console.log(jsonString); //输出 '{"name":"Tom","age":21,"gender":"male"}' ``` 在处理JSON字符串时,我们需要注意一些安全问题。首先,我们应该始终验证输入的JSON字符串是否有效。这可以通过尝试解析JSON字符串并检查是否发生了解析错误来实现。另外,我们还应该注意JSON字符串中的潜在安全漏洞,如JSON注入攻击。在通过用户输入的JSON字符串进行操作时,我们需要确保输入不包含恶意代码或攻击脚本。 总之,在JavaScript解析JSON字符串是非常重要的,它使得我们能够使用和交换复杂的数据结构。通过`JSON.parse()`和`JSON.stringify()`函数,我们可以轻松地将JSON数据转换为JavaScript对象或字符串,并进行操作和传输。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值