14

So I have a large JSON object i'm returning from the server, then building a datatable from it and displaying it on the form. This usually takes a few seconds.. so I was thinking of a loading bar. I have the logic behind the loading bar, however the loop that builds the hmtl data is locking down the browser and I cannot call out to the element i need to update.

Here is my function to do this:

function buildDataTable(db_table, container_id) {
    var $pb = $("<div id=\"progress-bar\"></div>");
    $(container_id).html($pb);
    $pb.progressbar({
        value: 0
    });
    $.post("post location", {
        view: "all"
    }, function (data) {
        var headers = "";
        var contents = "";
        var jsonObject = $.parseJSON(data);
        var tik = Math.round(jsonObject.length / 100);
    for (key in jsonObject[0]) {
            headers += "<th>" + key.replace(" ", "&nbsp;") + "</th>";
        }
        for (i in jsonObject) {
            contents += "<tr>";
            for (j in jsonObject[i]) {
                contents += "<td class=\"border-right\">" + jsonObject[i][j] + "</td>";
            }
            contents += "</tr>";
            if(Math.round(i/tik) == i/tik) {
/* if I run the alert (between popups) i can see the progressbar update, otherwise I see no update, the progressbar appears empty then the $(container_id) element is updated with the table i've generated */
                alert(''); 
                $pb.progressbar("value",i/tik);
            }
        }
        var html = "<table cellpadding=\"5\" cellspacing=\"0\"><thead><tr>" + headers + "</tr></thead><tbody>" + contents + "</tbody></table>";

        $(container_id).html(html);
        $(container_id).children("table:first").dataTable({
            "bJQueryUI": true,
            "sScrollX": "100%"
        });
    });
}
13
  • 1
    JavaScript is single threaded. You'll have to break your work up into pieces and call them in sequence using "setTimeout" to allow the GUI to update during processing, but even then the browser will still seem somewhat unresponsive. Commented Aug 9, 2011 at 15:04
  • So am I better to just use an animated gif and not show the real progress? Commented Aug 9, 2011 at 15:09
  • @maerics: I thought asynchronous requests opened up a new thread? Commented Aug 9, 2011 at 15:09
  • First, use the loop to generate the HTML code. Then, (when the loop has finished), find the element on the page and update it. Commented Aug 9, 2011 at 15:09
  • @Šime Vidas, that would not show the 'progress' of the load... Commented Aug 9, 2011 at 15:10

4 Answers 4

21

[Added my comment as an answer]

JavaScript is single threaded. You'll have to break your work up into pieces and call them in sequence using "setTimeout" to allow the GUI to update during processing (in between your calls) but even then the browser will still seem somewhat unresponsive.

Sign up to request clarification or add additional context in comments.

3 Comments

Actually the web workers give a good alternative to the 'setTimeout' solution...
@revers: yes, WebWorkers seems to have been designed for exactly this kind of problem; however, it's an HTML5 draft (last time I checked) so newer browsers will have some support but there will be differences in behavior. Older browsers will have to do something kludgey like I suggested.
Even leaving aside web workers, JavaScript, the language, has never been single-threaded. JavaScript is silent on the topic of threading, and even in 2011, multi-threaded environments were available (such as Rhino on the JVM, and a couple of NodeJS-like things that never took off -- multi-threaded programming is hard).
3

You can try using WebWorker: https://developer.mozilla.org/en/DOM/Worker
Thus worker are executed in parallel of the main thread, you cannot exactly achieve multi-threading using workers: you cannot modify the UI from a worker.
You can maybe create your grid as a string in a worker and when the worker finish, append it where you want.

2 Comments

Seems that their HTTP Secure is having issues.... cannot load any of the pages under https
You can also have a look at this page then. But as maerics mentions Web workers are quite new and are only supported by new browsers.
2

If you do all the building of the Database in a setTimeout, the rest of the page should be responsive.

You can construct the html elements in that function, and when it is ready, attach it to the DOM. You will also have to call functions or send events to update the display of the progress bar.

Edit after comment:

This will run in background and won't affect responsiveness of the page:

window.setTimeout(function() {buildDataTable(db_table, container_id)}, 0);

You already update your progressbar from your function, so this should do it.

However, you might want to decouple the code generating the datatable from the code updating the progressbar.

2 Comments

Can you clerify this? wrap the function call in setTimeout(function(){ Function Call },0);
If buildDataTable is a longruning task (and OP says it is) then this approach will not solve the unresponsive UI problem as it will block while it's running (it just might allow something else just before it starts running). You would need to break the task down into smaller chunks and call setTimeout for each of these to get some kind of timesharing.
1

So it appears the only clean way to do this in my application is to process the json on the server and build the html there. Then return the html to the browser via $.post()

The progress bar will be lost. however I can use a infinite loading gif...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.