AJAX progress bar

With few lines of JavaScript and CSS it’s possible to make simple AJAX progress bar. JavaScript will periodically ask for progress value and server will respond with JSON data. Progress value is being read and displayed as DIV element width. To start progress bar demo, click on Start button and wait few seconds to begin. To watch how this page sends requests to Web server just open DOM inspector “Network” card.

 


More precisely, every 1000ms sendRequest() method sends request to server – see setInterval line in pollingStart() method. ajax-progress-bar.php responds and requestHandler() processes received JSON data. Progress value in JSON data has meaning of job completion (in percentage).

In following JavaScript source, please focus on sending and handling requests. Property onreadystatechange is function that receives server feedback. It’s important to note that feedback function must be assigned before each send, because after request is completed, onreadystatechange property is cleared.

// create redips container
let redips = {};

// initialization
redips.init = function () {
    // set reference to the progress bar DIV
    redips.div = document.getElementById('progress');
    // create XML HTTP request object
    redips.xhr = new XMLHttpRequest();
    // set interval ID to false
    redips.intervalID = false;
};

// send request to server
redips.sendRequest = function () {
    let numberMax = 20, // limit number of requests (needed only for demo)
        xhr = redips.xhr;
    // if server is asked less than numberMax
    if (redips.number < numberMax) {
        xhr.open('GET', 'ajax-progress-bar.php', true); // open asynchronus request
        xhr.onreadystatechange = redips.requestHandler; // set request handler
        xhr.send(null);                                    // send request
        redips.number++;                                // increase counter
    }
    // otherwise stop polling
    else {
        redips.pollingStop();
    }
};

// request handler
redips.requestHandler = function () {
    let xhr = redips.xhr;
    // if operation is completed (readyState === 4)
    if (xhr.readyState === XMLHttpRequest.DONE) {
        // if HTTP status is OK
        if (xhr.status === 200) {
            // get progress level from JSON output
            let level = JSON.parse(xhr.responseText).progress;
            // set progress bar width and innerHTML
            redips.div.style.width = redips.div.innerHTML = level + '%';
        }
        // if request status is not OK
        else {
            redips.div.style.width = '100%';
            redips.div.innerHTML = 'Error:[' + xhr.status + ']' + xhr.statusText;
        }
    }
};

// button start
redips.pollingStart = function () {
    if (!redips.intervalID) {
        // reset number of requests
        redips.number = 0;
        // start polling
        redips.intervalID = window.setInterval(redips.sendRequest, 1000);
    }
};

// button stop
redips.pollingStop = function () {
    let xhr = redips.xhr;
    // abort current request if status is 1, 2, 3
    // 0: request not initialized
    // 1: server connection established
    // 2: request received
    // 3: processing request
    // 4: request finished and response is ready
    if (xhr.readyState > 0 && xhr.readyState < 4) {
        xhr.abort();
    }
    window.clearInterval(redips.intervalID);
    redips.intervalID = false;
    // display 'Demo stopped'
    redips.div.style.width = '100%';
    redips.div.innerHTML = 'Demo stopped';
};

// add onload event listener
if (window.addEventListener) {
    window.addEventListener('load', redips.init, false);
}
else if (window.attachEvent) {
    window.attachEvent('onload', redips.init);
}

Here you can see ajax-progress-bar.php source (how job progress is emulated). In your case you will have to calculate percentage of completion and return it in JSON format. Caching for ajax-progress-bar.php should be disabled. Many proxies and clients can be forced to disable caching with “header” lines pragma, cache-control and expires.

<?php
// no cache
header('Pragma: no-cache');
// HTTP/1.1
header('Cache-Control: no-cache, must-revalidate');
// date in past
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
// prepare demo progress value
$progress = (time() % 50) * 2;
// return progress level in JSON format
print "{\"progress\": \"$progress\"}";
?>

Download source code: redips6.tar.gz

11/21/2010 – Code tested with JSLint & enabled source download
06/10/2011 – Added limit of how many times to request the server (automatic demo stop)
26/03/2020 – Code tested with ESLint & changed to use JSON instead of XML

64 thoughts on “AJAX progress bar”

  1. I just wanna thank you for your JS snippet it was very helpful for me.

    Using it I proceed a large treatment that takes 2 hours It works perfectly on Mozilla and Chrome,
    but the Internet explorer abort the XMLHttpRequest.

  2. @Said – Please, can you specify in which IE version you have problem with this code (because IE8 works just fine)? Maybe initXMLHttpClient() method should be extended to support some new features from Microsoft browsers (this would not surprise me). :)

  3. Hey, great script, but is there a way to handle multiple progress bars? I created div id’s for progress, progress2, progress3 etc, but how would I handle it in the script.js?

  4. What is this?
    I don’t understand your AJAX progress bar example.
    Where should I inject my database insertion in PHP?
    Can you help me please?

Leave a Comment