JSON search by key name

JavaScript performance comparison

Revision 2 of this test case created by tomByrer

Info

Compare 2 methods to get values in complex objects by key name, using different sources.

Method 1: Loop object recursive

Method 2: Search in JSON string with a lexer

Source 1: Object

Source 2: JSON string

JSON.parse and JSON.stringify are slow methods, so in some cases it's faster to search in the JSON string with a simple lexer. In this case the resulting string is probably smaller than the complete JSON string, so call of JSON.parse only for the result is faster.

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    (function (global) {
        var rsimple = /^(?:(?:-?(?=[1-9]|0(?!\d))\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(?:true|false|null)|(?:"(?:[^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"))\s*:?\s*/,
                ropen = /^(?:\[|\{)\s*/,
                rnext = /^,\s*/,
                rclose = /^(?:\]|\})\s*/;
   
        function escapeRegexp(string) {
                return (string)
                        .replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1");
        }
   
        function lexer(json) {
                var part = "";
                repl = function (all) {
                        part += all;
                        return "";
                },
                i = 0;
                while (json.length && i >= 0) {
                        if (rsimple.test(json)) {
                                json = json.replace(rsimple, repl);
                        }
                        else if (ropen.test(json)) {
                                json = json.replace(ropen, repl);
                                i++;
                        }
                        else if (rclose.test(json) && i > 0) {
                                json = json.replace(rclose, repl);
                                i--;
                        }
                        else if (rnext.test(json) && i > 0) {
                                json = json.replace(rnext, repl);
                        }
                        else {
                                i = -1;
                        }
                }
                return part;
        }
   
        global.findInJSON = function (keyname, json, g) {
                var rfind = new RegExp("\"" + escapeRegexp(keyname) + "\"\\s*:\\s*([\\s\\S]+)$", ""),
                        results = [];
                function handle(json) {
                        var found = rfind.exec(json);
                        if (found) {
                                results.push(lexer(found[1]));
                                // Search global
                                if (g) {
                                        handle(found[1]);
                                }
                        }
                }
   
                // Convert to JSON and start search
                handle(json);
   
                // Get results array from JSON string
                return "[" + results.join(",") + "]";
        };
       
        global.findInObject = function (keyname, object, g) {
                var results = [];
       
                function handle(object) {
                       
                        for (var key in object) {
                                if (key === keyname) {
                                        results.push(object[key]);
                                       
                                        if (!g) {
                                                return;
                                        }
                                }
                               
                                if (typeof object[key] === "object") {
                                        handle(object[key]);
                                }
                        }
                }
       
                handle(object);
       
                return results;
        };
   
    }(this));
   
    var testDataObject = {};
    var http_request = new XMLHttpRequest();
    http_request.open("GET", "http://cdnjs.com/packages.json", true);
    http_request.onreadystatechange = function () {
        if (http_request.readyState == 4 && http_request.status == 200) { //done && ok
            testDataObject = JSON.parse(http_request.responseText);
        }
    };
    http_request.send(null);
   
    var testDataJSON = JSON.stringify(testDataObject);
};
</script>

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Loop source: Object
this.findInObject("name", testDataObject, true);
pending…
Loop source: JSON (needs to convert input)
this.findInObject("name", JSON.parse(testDataJSON), true);
pending…
Lexer source: Object (needs to convert input and output)
JSON.parse(this.findInJSON("name", JSON.stringify(testDataObject), true));
pending…
Lexer source: JSON (needs to convert output)
JSON.parse(this.findInJSON("name", testDataJSON, true));
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