Last Updated: November 19, 2020
·
50.12K
· lukemadhanga

Get progress of an AJAX request

So you write a cool AJAX application, but you're scared that people with über slow connections will get impatient and think that the site is broken. Obviously, the first thing to do is optimize by making sure you're not transferring too much data. That said, there are times when there is nothing much you can do about it, e.g. an image upload via ajax. The alternative would be to calculate the progress of the upload and show the user how much longer they have to wait

$.ajax({
    url: path,
    type: 'post',
    data: {payload: payload},
    xhr: function () {
        var xhr = $.ajaxSettings.xhr();
        xhr.onprogress = function e() {
            // For downloads
            if (e.lengthComputable) {
                console.log(e.loaded / e.total);
            }
        };
        xhr.upload.onprogress = function (e) {
            // For uploads
            if (e.lengthComputable) {
                console.log(e.loaded / e.total);
            }
        };
        return xhr;
    }
}).done(function (e) {
    // Do something
}).fail(function (e) {
    // Do something
});

NOTE

You can only use this calculate the progress of a download or upload. If your server is calculating a request slowly, there is no way of informing the user of any form of progress

The magic in the above code is the xhr property in the $.ajax() settings. What we do here is retrieve the original xhr object, and use the data therein to calculate the progress.

For uploads, the content-length is generally calculated for you by the browser, but for downloads, you have to make sure that you have a VALID (i.e. the correct amount of bytes) content-length header.

PHP

For the PHP developers, you can set the content-length header by doing the following

# E.G. For a large page
header('Content-Length: ' . mb_strlen($content));
# E.G. For a file
header('Content-Length: ' . filesize($download));

Related protips:

jQuery: When to use $(document).ready() and when $(window).load()