AJAX progress bar

With few lines of JavaScript and CSS you can make a simple AJAX progress bar. JavaScript will periodically ask for progress value and server will respond with XML. Progress value should be extracted from the XML and displayed as width of the DIV element. To start progress bar in this example, please click on the Start button and wait for a second to begin. If you have installed Firebug, open Net tab and watch how this page sends request to the Web server.

More precisely, every 1000ms send_request() function sends request to the server (see setInterval line in polling_start() function). ajax-progress-bar.php returns XML and request_handler() processes received XML. Progress value from XML has meaning of percentage completion of a job.

In the following JavaScript source, please focus to the sending and handling requests. Initialization of the XMLHttpRequest is written in the cross-browser manner and there’s nothing more to add. The onreadystatechange property is a function that receives the feedback. It is important to note that the feedback function must be assigned before each send, because upon request completion the onreadystatechange property is reset. This is evident in the Mozilla and Firefox source.

// create XMLHttp request object in a cross-browser manner
initXMLHttpClient = function () {
    var XMLHTTP_IDS,
        success = false,
    // Mozilla/Chrome/Safari/IE7+ (normal browsers)
    try {
        xmlhttp = new XMLHttpRequest(); 
    // IE(?!)
    catch (e1) {
                        'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' ];
        for (i = 0; i < XMLHTTP_IDS.length && !success; i++) {
            try {
                success = true;
                xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]);
            catch (e2) {}
        if (!success) {
            throw new Error('Unable to create XMLHttpRequest!');
    return xmlhttp;

// send request to the server
send_request = function () {
    if (number < number_max) {
        request.open('GET', 'ajax-progress-bar.php', true); // open asynchronus request
        request.onreadystatechange = request_handler;       // set request handler    
        request.send(null);                                 // send request
        number++;                                           // increase counter
    else {

// request handler (started from send_request)
request_handler = function () {
    var level;
    if (request.readyState === 4) {   // if state = 4 (operation is completed)
        if (request.status === 200) { // and the HTTP status is OK
            // get progress from the XML node and set progress bar width and innerHTML
            level = request.responseXML.getElementsByTagName('PROGRESS')[0].firstChild;
            progress.style.width = progress.innerHTML = level.nodeValue + '%';
        else { // if request status is not OK
            progress.style.width = '100%';
            progress.innerHTML = 'Error:[' + request.status + ']' + request.statusText;

// button start
polling_start = function () {
    if (!intervalID) {
        // set initial value for current number of requests
        number = 0;
        // start polling
        intervalID = window.setInterval('send_request()', 1000);

// button stop
polling_stop = function () {
    // 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 (0 < request.readyState && request.readyState < 4) {
    intervalID = false;
    // display 'Demo stopped'
    progress.style.width = '100%';
    progress.innerHTML = 'Demo stopped';

Here you can see the source of ajax-progress-bar.php (how is job progress emulated). In your case you will have to calculate percentage of completion and return it in XML 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.

// no cache
header('Pragma: no-cache');
// HTTP/1.1
header('Cache-Control: no-cache, must-revalidate');
// date in the past
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
// define XML content type
header('Content-type: text/xml');
// print XML header
print '<?xml version="1.0"?>';
// prepare demo progress value
$progress = (mktime() % 50) * 2;
<DOCUMENT><PROGRESS><?php print $progress ?></PROGRESS></DOCUMENT>

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)

63 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?

Leave a Comment