3

I want to show a list with 1000 rows using Json that's support by Struts2 like pug-in. I use flexigrid (jquery) to parse 1000 rows to display. But it's so slow, and sometimes my browser crashes. (Firefox & IE).

So, what is the fastest Javascript framework to parse about 1000 rows?

Jørn Schou-Rode
  • 37,718
  • 15
  • 88
  • 122
m0z4rt
  • 1,055
  • 2
  • 17
  • 25
  • 3
    Can you show your current code? If I had to guess, it's not the JSON parser that slow, but the way you are updating the DOM with said data. – Matt Jan 18 '10 at 13:55
  • Are you required to use JSON? A plain format like CSV is much quicker to parse than JSON. – Gumbo Jan 18 '10 at 13:59
  • 2
    @Gumbo: *True* CSV is a real pain to parse; it's not just a matter of `data.split(",")`. Whereas JSON is a doddle (and speed and conformance are improving as browsers improve their support for explicitly parsing JSON, since folks have figured out it's a Bad Idea to just `eval` it). Besides, I doubt the data parse is the real issue. – T.J. Crowder Jan 18 '10 at 14:00
  • @T.J. Crowder: But in JSON there are different data types that can be nested too. In CSV you have just two: quoted and unquoted values. And if your data doesn’t require quotation, you do can use something like `data.split(",")`. – Gumbo Jan 18 '10 at 14:09
  • @Gumbo: Yes indeed. As I said, *true* CSV is a pain. CSV-lite, if you will (no commas other than separators, etc.) is indeed that easy. But again, I doubt the data parsing is the issue. – T.J. Crowder Jan 18 '10 at 14:41
  • @T.J. Crowder: *True* CSV is not much harder though there are several definitions. I would even say it’s easier as you just have to handle two data types (quoted and unquoted) instead of several more like in JSON. – Gumbo Jan 18 '10 at 15:01
  • @Gumbo: And the quoted ones can have quotes in them (or anything else), line breaks (which is a pain if you're trying to process in chunks), commas... But hey, we can just disagree. :-) – T.J. Crowder Jan 18 '10 at 17:22

5 Answers5

16

What is the fastest JSON parser for JavaScript?

eval or when available, native JSON parser, at least in Chrome, Safari, Firefox 3.something, Opera 10.50, and even IE8 (only in IE8-mode)

Jani Hartikainen
  • 42,745
  • 10
  • 68
  • 86
6

Show the user what they want to see.

Show 50 rows, add a filter or a search.

If you really think that data should be reachable in a single page, maybe what you want is to fetch data while the user scrolls (and thus pick up smaller portions at a time).

cgp
  • 41,026
  • 12
  • 101
  • 131
  • I get a list return by Oracle procedure, so that it not changeable, thus, can not use scrollable ResultSet with Oracle.(limitation) – m0z4rt Jan 19 '10 at 12:13
  • 2
    Still, cache the data somewhere, be it in the application layer or whatnot, and then page it from there. Of course, I would still be surprised if there was no way to leave the data in some temporary Oracle table (or something along those lines) - but it doesn't change the fact you can cache it somewhere else. – cgp Jan 19 '10 at 12:26
  • plz give me more information about caching with spring jdbc and oracle, thanks u :) – m0z4rt Jan 21 '10 at 01:07
2

I don't think you'll get acceptable performance from just about any grid component showing 1,000 at the same time, especially not on IE (even IE8). But most grids should be able to support having 1,000 in memory (well, depending on how big they are) and displaying a window into them (say, 20 rows, 40 rows, etc.) with paging and filtering options, without a significant performance problem. That would be a better user experience as well, I would think.

Edit

I got curious enough to check, and yeah, JSON parse time is not the problem; it'll be the rendering. Below is an example of very, very simple (not production) paging entirely client-side. On my netbook, IE7 parses the 1,000 rows of simple JSON objects in 36ms, so even complex objects shouldn't be an issue. That's using Prototype's evalJSON, which (even now) just defers to eval and puts the data in parentheses (they'll be changing that).

1000rows.html

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>1,000 Row Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
</style>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js'></script>
<script type='text/javascript' src='1000rows.js'></script>
</head>
<body><div>
<input type='button' id='btnLoadData' value='Load Data'>
<input type='button' id='btnNext' value='Next'>
<input type='button' id='btnPrevious' value='Previous'>
<table>
<thead>
<tr><th>Name</th><th>Description</th><th>Count</th></tr>
</thead>
<tfoot>
<tr><th colspan='3' id='theLabel'></th></tr>
</tfoot>
<tbody id='theData'>
<tr><td colspan='3'></td></tr>
</tbody>
</table>
<hr>
<div id='log'></div>
</div></body>
</html>

1000rows.js (using Prototype; jQuery would be different but similar)

(function() {
    var data, windowTop, WINDOW_SIZE;

    // "Constant" for the size of our window into the data
    WINDOW_SIZE = 20;   // Rows

    // No data yet
    clearData();

    // Hook up our observers when we can
    document.observe('dom:loaded', function() {
        $('btnLoadData').observe('click', loadData);
        $('btnNext').observe('click', function(event) {
            event.stop();
            updateWindow(WINDOW_SIZE);
        });
        $('btnPrevious').observe('click', function(event) {
            event.stop();
            updateWindow(-WINDOW_SIZE);
        });
    });

    // Clear our data to a known state
    function clearData() {
        data = [];
        windowTop = 0;
    }

    // Click handler for the load data button
    function loadData() {
        var success;

        log("Loading data..");
        clearData();
        updateWindow();
        success = false;

        // Note: Using text/plain rather than application/json so
        // Prototype doesn't parse the data for me, so I can measure
        // how long it takes to do it.
        new Ajax.Request("data.txt", {
            onSuccess: function(response) {
                var start, duration;

                success = true;
                log("Got data, parsing");
                start = new Date().getTime();
                data = response.responseText.evalJSON();
                duration = new Date().getTime() - start;
                log("Data parsed in " + duration + "ms");
                updateWindow.defer();
            }
        });
    }

    function updateWindow(offset) {
        var dataElement, labelElement, markup, index, template;

        // Get the target element
        dataElement = $('theData');
        labelElement = $('theLabel');
        if (!dataElement || !labelElement) {
            return;
        }

        // If no data, simply say that
        if (!data || data.length <= 0) {
            dataElement.update("");
            labelElement.update("No information");
            return;
        }

        // Ensure that windowTop is rational
        if (WINDOW_SIZE > data.length) {
            windowTop = 0;
        }
        else {
            if (typeof offset == 'number') {
                windowTop += offset;
            }
            if (windowTop + WINDOW_SIZE > data.length) {
                windowTop = data.length - WINDOW_SIZE;
            }
            if (windowTop < 0) {
                windowTop = 0;
            }
        }

        template = new Template(
            "<tr><td>#{name}</td><td>#{description}</td><td>#{count}</td></tr>"
        );

        markup = "";
        index = windowTop + WINDOW_SIZE - 1;
        if (index >= data.length) {
            index = data.length - 1;
        }
        $('theLabel').update('Showing rows ' + windowTop + ' through ' + index);
        while (index >= windowTop) {
            markup = template.evaluate(data[index]) + markup;
            --index;
        }

        dataElement.update(markup);
    }

    // Log a message
    function log(msg) {
        $('log').appendChild(new Element('p').update(msg));
    }
})();

data.txt (quite boring, of course)

[
    {"name": "Name #0001", "description": "Description #0001", "count": 1},
    {"name": "Name #0002", "description": "Description #0002", "count": 2},
    {"name": "Name #0003", "description": "Description #0003", "count": 3},
    ...
    {"name": "Name #1000", "description": "Description #1000", "count": 1000}
]

...a full copy of data.txt can be found here.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

1,000 rows of what? jQuery is actually pretty quick, especially since performance upgrades in version 1.4 (released just days ago). If you're experiencing problems showing 1,000 rows, I would first ask you why you're showing that many - no human ought to have to scroll that much. And second, is all of the information crucial, and are you only passing crucial information into the JSON value. And lastly, are you making your DOM unnecessarily-complicated with the way you're adding the data?

Again, if you're querying only what you need to show, and you're showing a reasonable about of data (posting 1,000 rows on the screen isn't reasonable), jQuery will be more than sufficient for your needs.

Sampson
  • 265,109
  • 74
  • 539
  • 565
  • plz check my answer comment above, I use Flexigrid to load 1000rows, I think the cause of problem my by Fexigrid :), I will update more about jquery thanks u. :) – m0z4rt Jan 21 '10 at 01:26
1

If you really want speed, the javascript eval("..."); function is the fastest. Unfortunately it's not safe as it can execute malicious javascript.

There's also the javascript JSON Parser (found here) from JSON.org. They've written the javascript to parse JSON strings to create a JSON object (I've heard that debugging using Firebug, a Firefox add-ons, creates an array of JSON objects but I've never tried it).

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228