2

I want to display data on a webpage as it comes, let's say I have a tracert on a server and it may take longish time, but I want to show the data as it comes.

If I make it like this:

 $.ajax({
         url: '/cgi-bin/trace.cgi',
         dataType: 'text',
         async: true,
         cache: false,
         success: function (response) {
           $('#traceOut').append(response);
         }
        });

it will only be called when we are done with the cgi request.

I could do it directly with XMLHttpRequest, onreadystatechange and xmlhttp.readyState==3 This works ok in Firefox but in Chrome it only dumps data as it reaches 2k.

How do I do this in jQuery?

Roman Goyenko
  • 6,965
  • 5
  • 48
  • 81

1 Answers1

0

It is possible, with polling. The tricky part will be coordinating the process for multiple users on the server side. I'll explain the workflow below.

The Method

/**
 * Polls a URL until server indicates task is complete,
 * then sends a final request for those results.
 * 
 * Requires jQuery 1.4+.
 */
function poll(params) {

    // offer default params
    params = $.extend({
        error: function(xhr, status, err) {
            console.log('Network error: ' + status + ', ' + err);
        },
        progress: function(prog) {
            console.log(prog);
        },
        timeoutMillis: 600000,    // 10 minutes
        intervalMillis: 3000      // 3 seconds
    }, params);

    // kickoff
    _poll(params);

    function _poll(params) {
        $.ajax({
            url: params.url,
            type: 'GET',
            dataType: 'json',
            timeout: params.timeoutMillis,
            data: 'action=poll',
            success: (function(response, status, xhr) {
                if ('progress' in response) {
                    params.progress('Progress: ' + response.progress);
                }
                if ('status' in response) {
                    if (response.status == 'pending') {
                        // slight delay, then poll again
                        // (non-recursive!)
                        setTimeout((function() {
                            _poll(params);
                        }), params.intervalMillis);
                    }
                    else if (response.status == 'cancelled') {
                        params.progress("Task was cancelled");
                    }
                    else {
                        params.progress("Task complete");
                        // done polling; get the results
                        $.ajax({
                            url: params.url,
                            type: 'GET',
                            timeout: params.timeoutMillis,
                            data: 'action=results',
                            success: params.success,
                            error: params.error
                        });
                    }
                }
            }),
            error: params.error
        });
    }
}

Example usage

poll({
    url: '/cgi-bin/trace.cgi',
    progress: function(prog) {
        $('body #progress').text(prog);
    },
    success: function(response, status, xhr) {
        $('body').html(response);
    }
});

Workflow

This method will send a request to the server with parameter "action" set to "poll". The CGI script should launch its background task, persist some state in the user session, and respond with JSON-formatted strings:

{"status": "pending", "progress": "0%"}

The browser will repeatedly issue these "action=poll" requests until the response indicates completion. The CGI script must keep track of the task's progress and respond to the browser accordingly. This will involve session handling and concurrency:

{"status": "pending", "progress": "25%"}
{"status": "pending", "progress": "50%"}
{"status": "pending", "progress": "75%"}
{"status": "complete"}

The browser will then issue a "action=results" request to receive the background task's final payload. In this example, it's just HTML:

"<p>The answer is: 42</p>"
Joe Coder
  • 4,498
  • 31
  • 41
  • Well, the issue I am dealing with is not to show the progress, but to show data as it comes. I don't know what the progress % is at the trace route, I am trying to make the page more interactive by showing data as it comes. – Roman Goyenko Sep 05 '12 at 14:07
  • Yes but you could send any textual data as "progress" in the "pending" responses. Then change the progress() function in the example to populate the browser with this data. Are you rendering the data as HTML? Have you yet written the server-side logic for pulling the data as it comes and rendering it as HTML? You must use polling similar to what I've described here. – Joe Coder Sep 05 '12 at 17:56