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

🕒 2026-01-05 16:13:42
📁 JSON学习教程
作者:JSONLA小编

一、JSON 解析技术背景

JSON(JavaScript Object Notation)作为轻量级数据交换格式,已成为前后端交互的事实标准。在浏览器端解析 JSON 字符串本质上是将字符串转换为可操作的 JavaScript 对象,这一过程的性能直接影响前端应用的响应速度,尤其是在处理大量数据(如列表渲染、大数据可视化)时,解析效率的差异会被显著放大。需要明确的是,不同解析方式的底层原理存在本质区别:

  • eval():属于 JavaScript 解释器的核心功能,会执行传入的任意代码字符串,解析 JSON 时需用括号包裹以避免语法歧义(eval("(" + jsonStr + ")")),但存在安全风险(可能执行恶意代码)。
  • new Function():通过动态创建函数并执行,本质是编译后执行,相比 eval 少了部分解释器的预处理步骤,在部分引擎下效率更高。
  • JSON.parse():浏览器原生实现的 JSON 解析器,基于 ECMAScript 5 规范,仅解析 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}'; 

补充说明:测试用 JSON 字符串包含嵌套对象和数组,模拟真实业务场景(如列表数据返回),10000 次循环可有效放大性能差异,避免单次执行的误差。

2. 循环解析并记录时间

eval 方法

var beginTime = new Date(); 

for ( i = 0; i < count; i++ ) { 

o = eval( "(" + jsonString + ")" ); 

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

补充说明eval 执行时会启动 JavaScript 完整解释器,不仅解析 JSON,还会检查字符串中的可执行代码,这是其性能和安全的双重短板。

new Function 方法

var beginTime = new Date(); 

for ( i = 0; i < count; i++ ) { 

o = new Function( "return " + jsonString )(); 

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

补充说明new Function 创建的函数会被 JavaScript 引擎预编译,执行时跳过解释步骤,在 Gecko 引擎(Firefox)中编译优化更明显,因此性能优于 eval。

原生 JSON.parse 方法

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!" ); 

补充说明:原生JSON.parse由浏览器底层(C/C++)实现,不经过 JavaScript 解释器,且针对 JSON 格式做了专项优化,是理论上最优的解析方式,同时杜绝了代码注入风险。

三、测试对象与环境

选择目前主流的浏览器(不考虑 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. Chrome/Safari(WebKit 引擎)性能领先:WebKit 的 JavaScript 引擎(JSCore)对动态代码执行(eval/Function)做了极致优化,即时编译(JIT)技术大幅提升了执行效率。
  2. Firefox(Gecko 引擎)表现差异:Firefox 早期版本对 eval 的优化较弱,但 new Function 因预编译特性表现更好;插件(如 Firebug)会开启调试钩子,显著拖慢执行速度。
  3. IE 系列迭代优化:IE8 首次引入原生 JSON 对象,脱离了纯 JavaScript 解析的低效模式,性能大幅超越 IE6/7。

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 ) ); 

设计思路
  • 优先级:原生JSON.parse > 引擎适配方法 > eval,兼顾性能与安全性。
  • 封装代价:函数调用会带来约 5%-10% 的性能损耗,但换来了跨浏览器的一致性。
  • 安全提示:封装层可增加 JSON 格式校验(如正则),避免非 JSON 字符串传入导致的执行错误。

补充测试

1. 禁用 Firefox 插件后的测试

补充结论:调试工具(如 Firebug)会监听代码执行、记录调用栈,导致 JavaScript 执行效率下降 30%-50%,生产环境无插件时 Firefox 的解析性能可恢复至主流水平。  

2. 动态 JSON 字符串测试(避免缓存优化)

//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 ) ); 

 // 其他方法同理修改...

WebKit 引擎会缓存静态字符串的 eval 执行结果,动态字符串测试更贴近真实场景(每次返回的 JSON 数据不同),此时 Opera/IE8 的原生解析优势凸显,因为原生方法不依赖字符串缓存优化。

五、结论

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

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

现代开发补充建议

  1. 兼容性兜底:实际开发中可使用成熟库(如 JSON3、jQuery.parseJSON),而非手动封装,这些库已兼容所有浏览器并处理了边界情况(如非法 JSON 字符串)。
  2. 安全优先:无论性能如何,禁止在生产环境用 eval 解析不可信的 JSON 字符串(如用户输入、第三方接口返回),避免 XSS 或代码注入攻击。
  3. 现代浏览器最优解:目前所有现代浏览器(IE10+、Chrome、Firefox、Safari)均支持原生JSON.parse,其性能和安全性均为最优,无需再兼容老旧方法。

六、完整代码

<!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. 解析方式核心差异:原生JSON.parse(底层实现、安全)> new Function(预编译)> eval(全量解释、有风险),性能排序随引擎优化略有变化,但原生方法始终是首选。
  2. 测试注意事项:静态 JSON 字符串测试存在缓存优化干扰,动态字符串测试更贴近真实场景;浏览器插件(如调试工具)会显著影响性能测试结果。
  3. 现代开发实践:优先使用原生JSON.parse,老旧浏览器通过成熟库兜底,杜绝用 eval 解析不可信数据,兼顾性能与安全。


相关推荐

正在加载... ...