JSON libraries

JavaScript performance comparison

Test case created

Info

Douglas Crockford provides three different JSON parsing functions.

json2.js - Uses 'eval' for parsing
json_parse.js - Uses recursive descent for parsing
json_parse_state.js - Uses a state machine for parsing

There's also json3.js by Kit Cambridge that uses a non-eval approach.

Preparation code

<script>
// Force usage of non-native implementations
window.JSON = undefined;
</script>

<script>
// I was getting a '403 Forbidden' when trying to link to github directly
var JSON;JSON||(JSON={});
(function(){function k(a){return 10>a?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return"string"===typeof c?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function m(a,j){var c,d,h,n,g=e,f,b=j[a];b&&"object"===typeof b&&"function"===typeof b.toJSON&&(b=b.toJSON(a));"function"===typeof i&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?""+b:"null";case "boolean":case "null":return""+b;
case "object":if(!b)return"null";e+=l;f=[];if("[object Array]"===Object.prototype.toString.apply(b)){n=b.length;for(c=0;c<n;c+=1)f[c]=m(c,b)||"null";h=0===f.length?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(i&&"object"===typeof i){n=i.length;for(c=0;c<n;c+=1)"string"===typeof i[c]&&(d=i[c],(h=m(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=m(d,b))&&f.push(o(d)+(e?": ":":")+h);h=0===f.length?"{}":e?"{\n"+e+f.join(",\n"+
e)+"\n"+g+"}":"{"+f.join(",")+"}";e=g;return h}}"function"!==typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,l,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;"function"!==typeof JSON.stringify&&(JSON.stringify=function(a,j,c){var d;l=e="";if(typeof c==="number")for(d=0;d<c;d=d+1)l=l+" ";else typeof c==="string"&&(l=c);if((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return m("",
{"":a})});"function"!==typeof JSON.parse&&(JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&typeof b==="object")for(g in b)if(Object.prototype.hasOwnProperty.call(b,g)){f=c(b,g);f!==void 0?b[g]=f:delete b[g]}return e.call(a,d,b)}var d,a=""+a;q.lastIndex=0;q.test(a)&&(a=a.replace(q,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){d=eval("("+a+")");return typeof e==="function"?c({"":d},""):d}throw new SyntaxError("JSON.parse");})})();
</script>

<script src="https://raw.github.com/douglascrockford/JSON-js/master/json_parse.js"></script>

<script>
var json_parse_state=function(){function i(a){return a.replace(/\\(?:u(.{4})|([^u]))/g,function(a,b,c){return b?String.fromCharCode(parseInt(b,16)):h[c]})}var a,d,b,f,c,h={"\\":"\\",'"':'"',"/":"/",t:"\t",n:"\n",r:"\r",f:"\u000c",b:"\u0008"},j={go:function(){a="ok"},firstokey:function(){f=c;a="colon"},okey:function(){f=c;a="colon"},ovalue:function(){a="ocomma"},firstavalue:function(){a="acomma"},avalue:function(){a="acomma"}},k={go:function(){a="ok"},ovalue:function(){a="ocomma"},firstavalue:function(){a=
"acomma"},avalue:function(){a="acomma"}},l={"{":{go:function(){d.push({state:"ok"});b={};a="firstokey"},ovalue:function(){d.push({container:b,state:"ocomma",key:f});b={};a="firstokey"},firstavalue:function(){d.push({container:b,state:"acomma"});b={};a="firstokey"},avalue:function(){d.push({container:b,state:"acomma"});b={};a="firstokey"}},"}":{firstokey:function(){var e=d.pop();c=b;b=e.container;f=e.key;a=e.state},ocomma:function(){var e=d.pop();b[f]=c;c=b;b=e.container;f=e.key;a=e.state}},"[":{go:function(){d.push({state:"ok"});
b=[];a="firstavalue"},ovalue:function(){d.push({container:b,state:"ocomma",key:f});b=[];a="firstavalue"},firstavalue:function(){d.push({container:b,state:"acomma"});b=[];a="firstavalue"},avalue:function(){d.push({container:b,state:"acomma"});b=[];a="firstavalue"}},"]":{firstavalue:function(){var e=d.pop();c=b;b=e.container;f=e.key;a=e.state},acomma:function(){var e=d.pop();b.push(c);c=b;b=e.container;f=e.key;a=e.state}},":":{colon:function(){if(Object.hasOwnProperty.call(b,f))throw new SyntaxError('Duplicate key "'+
f+'"');a="ovalue"}},",":{ocomma:function(){b[f]=c;a="okey"},acomma:function(){b.push(c);a="avalue"}},"true":{go:function(){c=!0;a="ok"},ovalue:function(){c=!0;a="ocomma"},firstavalue:function(){c=!0;a="acomma"},avalue:function(){c=!0;a="acomma"}},"false":{go:function(){c=!1;a="ok"},ovalue:function(){c=!1;a="ocomma"},firstavalue:function(){c=!1;a="acomma"},avalue:function(){c=!1;a="acomma"}},"null":{go:function(){c=null;a="ok"},ovalue:function(){c=null;a="ocomma"},firstavalue:function(){c=null;a="acomma"},
avalue:function(){c=null;a="acomma"}}};return function(b,f){var g,h=/^[\x20\t\n\r]*(?:([,:\[\]{}]|true|false|null)|(-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)|"((?:[^\r\n\t\\\"]|\\(?:["\\\/trnfb]|u[0-9a-fA-F]{4}))*)")/;a="go";d=[];try{for(;;){g=h.exec(b);if(!g)break;if(g[1])l[g[1]][a]();else g[2]?(c=+g[2],k[a]()):(c=i(g[3]),j[a]());b=b.slice(g[0].length)}}catch(m){a=m}if("ok"!==a||/[^\x20\t\n\r]/.test(b))throw a instanceof SyntaxError?a:new SyntaxError("JSON");return"function"===typeof f?function n(a,b){var c,
e,d=a[b];if(d&&"object"===typeof d)for(c in d)Object.prototype.hasOwnProperty.call(d,c)&&(e=n(d,c),void 0!==e?d[c]=e:delete d[c]);return f.call(a,b,d)}({"":c},""):c}}();
</script>

<script>
/* JSON v3.2 | http://bestiejs.github.com/json3 | Copyright 2012, Kit Cambridge | http://kit.mit-license.org */
;(function(a,b){typeof define=="function"&&define.amd?define("json",["exports"],b):b(typeof exports=="object"&&exports||this.JSON3||(this.JSON3={}))})(this,function(a){var b={}.toString,c={}.hasOwnProperty,d=!1,e,f,g;e=typeof a.stringify=="function",f=typeof a.parse=="function",function(){var c='{"result":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}',g=new Date(-0xc782b5b800cec),h,i;d=typeof g.getUTCFullYear=="function"&&g.getUTCFullYear()==-109252&&typeof g.getUTCMonth=="function"&&g.getUTCMonth()===0&&typeof g.getUTCDate=="function"&&g.getUTCDate()==1,g=null;if(e){h=function(){return 1},h.toJSON=h;try{switch(!1){case a.stringify(0)==="0":case a.stringify(new 0..constructor)==="0":case a.stringify(new"".constructor)=='""':case a.stringify(b)===void 0:case a.stringify(void 0)===void 0:case a.stringify()===void 0:case a.stringify(h)==="1":case a.stringify([h])=="[1]":case a.stringify([void 0])=="[null]":case a.stringify(null)=="null":case a.stringify([void 0,b,null])=="[null,null,null]":case a.stringify({result:[h,true,false,null,"\0\b\n\f\r       "]})==c:case a.stringify(null,h)==="1":case a.stringify([1,2],null,1)=="[\n 1,\n 2\n]":case(h=new Date(-864e13)).getUTCFullYear()!=-271821||a.stringify(h)=='"-271821-04-20T00:00:00.000Z"':case(h=new Date(864e13)).getUTCFullYear()!=275760||a.stringify(h)=='"+275760-09-13T00:00:00.000Z"':case a.stringify(new Date(-621987552e5))=='"-000001-01-01T00:00:00.000Z"':case a.stringify(new Date(-1))=='"1969-12-31T23:59:59.999Z"':e=!1}}catch(j){e=!1}}if(f)try{if(a.parse("0")===0&&!a.parse(!1)){g=a.parse(c);if(f=g.result.length==5&&g.result[0]==1){try{f=!a.parse('"  "')}catch(j){}if(f)try{f=a.parse("+1")!=1&&a.parse("01")!=1}catch(j){}}}}catch(j){f=!1}}();if(!c||b.call(c)!="[object Function]")c=function(){var a,c={},d=c.constructor;return(c.__proto__=null,c.__proto__={toString:1},c).toString!=b?a=function(b){var c=this.__proto__,d=b in(this.__proto__=null,this);return this.__proto__=c,d}:a=function(b){var c=(this.constructor||d).prototype;return b in this&&!(b in c&&this[b]===c[b])},c=null,a}();g=function(){function g(){this.valueOf=0}var a,d,e,f=0;g.prototype.valueOf=0,a=new g;for(d in a)c.call(a,d)&&(f+=1);return a=null,f?f==2?e=function(d,e){var f={},g=b.call(d)=="[object Function]",h;for(h in d)(!g||h!="prototype")&&!c.call(f,h)&&(f[h]=1)&&c.call(d,h)&&e(h)}:e=function(d,e){var f=b.call(d)=="[object Function]",g,h;for(g in d)(!f||g!="prototype")&&c.call(d,g)&&!(h=g==="constructor")&&e(g);(h||c.call(d,"constructor"))&&e("constructor")}:(a=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],e=function(e,f){var g=b.call(e)=="[object Function]",h,i;for(h in e)(!g||h!="prototype")&&c.call(e,h)&&f(h);for(i=a.length;h=a[--i];c.call(e,h)&&f(h));}),e}();if(!e||e&&!d)a.stringify=function(){function h(a,b){return("000000"+(b||0)).slice(-a)}function i(b){var c='"',d=0,e;for(;e=b.charAt(d);d+=1)c+='\\"\b\f\n\r   '.indexOf(e)>-1?a[e]:e<" "?"\\u00"+h(2,e.charCodeAt(0).toString(16)):e;return c+'"'}function j(a,b){return e[b]+365*(a-1970)+f((a-1969+(b=+(b>1)))/4)-f((a-1901+b)/100)+f((a-1601+b)/400)}function k(a,e,l,m,n,o,p){var q=e[a],r,s,t,u,v,w,x,y,z,A;if(typeof q=="object"&&q)if(b.call(q)=="[object Date]"&&!c.call(q,"toJSON"))if(q>-1/0&&q<1/0){if(d)t=q.getUTCFullYear(),u=q.getUTCMonth(),s=q.getUTCDate();else{s=f(q/864e5);for(t=f(s/365.2425)+1970-1;j(t+1,0)<=s;t+=1);for(u=f((s-j(t,0))/30.42);j(t,u+1)<=s;u+=1);s=1+s-j(t,u)}q=(t<=0||t>=1e4?(t<0?"-":"+")+h(6,t<0?-t:t):h(4,t))+"-"+h(2,u+1)+"-"+h(2,s)+"T"+h(2,q.getUTCHours())+":"+h(2,q.getUTCMinutes())+":"+h(2,q.getUTCSeconds())+"."+h(3,q.getUTCMilliseconds())+"Z"}else q=null;else typeof q.toJSON=="function"&&(q=q.toJSON(a));l&&(q=l.call(e,a,q));if(q===null)return"null";r=b.call(q);switch(r){case"[object Boolean]":return""+q;case"[object Number]":return q>-1/0&&q<1/0?""+q:"null";case"[object String]":return i(q)}if(typeof q=="object"){for(y=p.length;y--;)if(p[y]==q)throw TypeError("Cyclic structures cannot be serialized."
);p.push(q),v=[],z=o,o+=n;if(r=="[object Array]"){for(x=0,y=q.length;x<y;A||(A=!0),x++)w=k(x,q,l,m,n,o,p),v.push(w===void 0?"null":w);return A?n?"[\n"+o+v.join(",\n"+o)+"\n"+z+"]":"["+v.join(",")+"]":"[]"}return g(m||q,function(a){var b=k(a,q,l,m,n,o,p);b!==void 0&&v.push(i(a)+":"+(n?" ":"")+b),A||(A=!0)}),A?n?"{\n"+o+v.join(",\n"+o)+"\n"+z+"}":"{"+v.join(",")+"}":"{}"}}function l(a,c,d){var e,f,g,h,i;if(typeof c=="function"||typeof c=="object"&&c)if(b.call(c)=="[object Function]")f=c;else if(b.call(c)=="[object Array]"){g={};for(h=c.length;h--;(i=c[h])&&(b.call(i)=="[object String]"||b.call(i)=="[object Number]")&&(g[i]=1));}if(d!=null&&d!==""&&d!==0)if(b.call(d)=="[object Number]"){if((d-=d%1)>0)for(e="",d>10&&(d=10);e.length<d;e+=" ");}else b.call(d)=="[object String]"&&(e=d.length<=10?d:d.slice(0,10));return k("",(i={},i[""]=a,i),f,g,e,"",[])}var a={"\\":"\\\\",'"':'\\"',"\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","   ":"\\t"},e=[0,31,59,90,120,151,181,212,243,273,304,334],f=Math.floor;return l}();return f||(a.parse=function(){function d(a){this.source=a,this.index=0}function e(){for(var b=this.source,d=this.source.length,e,f,g,h,i;this.index<d;){e=b.charAt(this.index);switch(e){case" ":case"\r":case"\n":case" ":this.index+=1;break;case"{":case"}":case"[":case"]":case":":case",":return this.index+=1,e;case'"':for(f="@",this.index+=1;this.index<d;){e=b.charAt(this.index);if(e<" ")throw SyntaxError("Unescaped control character in string.");if(e=="\\"){this.index+=1,e=b.charAt(this.index);if('\\"/btnfr'.indexOf(e)>-1)f+=a[e],this.index+=1;else{if(e!="u")throw SyntaxError("Invalid escape sequence in string.");g=this.index+=1;for(h=this.index+4;this.index<h;this.index+=1){e=b.charAt(this.index);if(!(e>="0"&&e<="9"||e>="a"&&e<="f"||e>="A"&&e<="F"))throw SyntaxError("Invalid Unicode escape sequence in string.")}f+=c("0x"+b.slice(g,this.index))}}else{if(e=='"')break;f+=e,this.index+=1}}if(b.charAt(this.index)=='"')return this.index+=1,f;throw SyntaxError("Unterminated string.");default:g=this.index,e=="-"&&(i=!0,e=b.charAt(this.index+=1));if(e>="0"&&e<="9"){if(e=="0"&&(e=b.charAt(this.index+1),e>="0"&&e<="9"))throw SyntaxError("Illegal octal literal.");i=!1;for(;this.index<d&&(e=b.charAt(this.index),e>="0"&&e<="9");this.index+=1);if(b.charAt(this.index)=="."){h=this.index+=1;for(;h<d&&(e=b.charAt(h),e>="0"&&e<="9");h+=1);if(h==this.index)throw SyntaxError("Illegal trailing decimal.");this.index=h}e=b.charAt(this.index);if(e=="e"||e=="E"){e=b.charAt(this.index+=1);if(e=="+"||e=="-")this.index+=1;for(h=this.index;h<d&&(e=b.charAt(h),e>="0"&&e<="9");h+=1);if(h==this.index)throw SyntaxError("Illegal empty exponent.");this.index=h}return+b.slice(g,this.index)}if(i)throw SyntaxError("Unexpected `-`.");if(e=="t"&&b.slice(this.index,this.index+4)=="true")return this.index+=4,!0;if(e=="f"&&b.slice(this.index,this.index+5)=="false")return this.index+=5,!1;if(e=="n"&&b.slice(this.index,this.index+4)=="null")return this.index+=4,null;throw SyntaxError("Unrecognized token.")}}return"$"}function f(a){var b,c,d;if(a=="$")throw SyntaxError("Unexpected end-of-file.");if(typeof a=="string"){if(a.charAt(0)=="@")return a.slice(1);switch(a){case"[":b=[];for(;;c||(c=!0)){a=this.lex();if(a=="]")break;if(c){if(a!=",")throw SyntaxError("A comma (`,`) must separate the previous array element from the next.");a=this.lex();if(a=="]")throw SyntaxError("Unexpected trailing `,` in array literal.")}if(a==",")throw SyntaxError("Unexpected `,` in array literal.");b.push(this.get(a))}return b;case"{":b={};for(;;c||(c=!0)){a=this.lex();if(a=="}")break;if(c){if(a!=",")throw SyntaxError("A comma (`,`) must separate the previous object member from the next.");a=this.lex();if(a=="}")throw SyntaxError("Unexpected trailing `,`. in object literal.")}if(a==",")throw SyntaxError("Unexpected `,` in object literal.");if(typeof a!="string"||a.charAt(0)!="@")throw SyntaxError("Object property names must be double-quoted strings.");if(this.lex()!=":")throw SyntaxError("A single colon (`:`) must separate each object property name from the value.");b[a.slice(1)]=this.get(this.lex
())}return b}throw SyntaxError("Expected `[` or `{`.")}return a}function h(a,c,d){var e=a[c],f,i;if(typeof e=="object"&&e)if(b.call(e)=="[object Array]")for(f=e.length;f--;)i=h(e,f,d),i===void 0?e.splice(f,1):e[f]=i;else g(e,function(a){var b=h(e,a,d);b===void 0?delete e[a]:e[a]=b});return d.call(a,c,e)}function i(a,c){var e=new d(""+a),f=e.get(e.lex()),g;if(e.lex()!="$")throw SyntaxError("Expected end-of-file.");return c&&b.call(c)=="[object Function]"?h((g={},g[""]=f,g),"",c):f}var a={"\\":"\\",'"':'"',"/":"/",b:"\b",t:"        ",n:"\n",f:"\f",r:"\r"},c="".constructor.fromCharCode;return d.prototype.lex=e,d.prototype.get=f,i}()),a})
</script>
<script>
Benchmark.prototype.setup = function() {
    var jsonString = '{"Hello":"World","anotherObj":{"bam":"pow","w":"tf"},"array":[1,2,3],"number":5,"date":"2012-04-25T14:08:36.879Z"}';
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
json2.js
var obj = JSON.parse(jsonString);
pending…
json_parse
var obj = json_parse(jsonString);
pending…
json_parse_state
var obj = json_parse_state(jsonString);
pending…
json3.js
var obj = JSON3.parse(jsonString);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment