[javascript] How to get progress from XMLHttpRequest

Is it possible to get the progress of an XMLHttpRequest (bytes uploaded, bytes downloaded)?

This would be useful to show a progress bar when the user is uploading a large file. The standard API doesn't seem to support it, but maybe there's some non-standard extension in any of the browsers out there? It seems like a pretty obvious feature to have after all, since the client knows how many bytes were uploaded/downloaded.

note: I'm aware of the "poll the server for progress" alternative (it's what I'm doing right now). the main problem with this (other than the complicated server-side code) is that typically, while uploading a big file, the user's connection is completely hosed, because most ISPs offer poor upstream. So making extra requests is not as responsive as I'd hoped. I was hoping there'd be a way (maybe non-standard) to get this information, which the browser has at all times.

This question is related to javascript ajax progress-bar

The answer is


The only way to do that with pure javascript is to implement some kind of polling mechanism. You will need to send ajax requests at fixed intervals (each 5 seconds for example) to get the number of bytes received by the server.

A more efficient way would be to use flash. The flex component FileReference dispatchs periodically a 'progress' event holding the number of bytes already uploaded. If you need to stick with javascript, bridges are available between actionscript and javascript. The good news is that this work has been already done for you :)

swfupload

This library allows to register a javascript handler on the flash progress event.

This solution has the hudge advantage of not requiring aditionnal resources on the server side.


_x000D_
_x000D_
<!DOCTYPE html>_x000D_
<html>_x000D_
<body>_x000D_
<p id="demo">result</p>_x000D_
<button type="button" onclick="get_post_ajax();">Change Content</button>_x000D_
<script type="text/javascript">_x000D_
 function update_progress(e)_x000D_
 {_x000D_
   if (e.lengthComputable)_x000D_
   {_x000D_
     var percentage = Math.round((e.loaded/e.total)*100);_x000D_
     console.log("percent " + percentage + '%' );_x000D_
   }_x000D_
   else _x000D_
   {_x000D_
    console.log("Unable to compute progress information since the total size is unknown");_x000D_
   }_x000D_
 }_x000D_
 function transfer_complete(e){console.log("The transfer is complete.");}_x000D_
 function transfer_failed(e){console.log("An error occurred while transferring the file.");}_x000D_
 function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}_x000D_
 function get_post_ajax()_x000D_
 {_x000D_
    var xhttp;_x000D_
    if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers} _x000D_
   else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5    _x000D_
    xhttp.onprogress = update_progress;_x000D_
  xhttp.addEventListener("load", transfer_complete, false);_x000D_
  xhttp.addEventListener("error", transfer_failed, false);_x000D_
  xhttp.addEventListener("abort", transfer_canceled, false);    _x000D_
    xhttp.onreadystatechange = function()_x000D_
    {_x000D_
      if (xhttp.readyState == 4 && xhttp.status == 200)_x000D_
      {_x000D_
         document.getElementById("demo").innerHTML = xhttp.responseText;_x000D_
      }_x000D_
    };_x000D_
   xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);_x000D_
   xhttp.send();_x000D_
 }_x000D_
</script>_x000D_
</body>_x000D_
</html>
_x000D_
_x000D_
_x000D_

Result


If you have access to your apache install and trust third-party code, you can use the apache upload progress module (if you use apache; there's also a nginx upload progress module).

Otherwise, you'd have to write a script that you can hit out of band to request the status of the file (checking the filesize of the tmp file for instance).

There's some work going on in firefox 3 I believe to add upload progress support to the browser, but that's not going to get into all the browsers and be widely adopted for a while (more's the pity).


For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.

For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.


Firefox supports XHR download progress events.


The only way to do that with pure javascript is to implement some kind of polling mechanism. You will need to send ajax requests at fixed intervals (each 5 seconds for example) to get the number of bytes received by the server.

A more efficient way would be to use flash. The flex component FileReference dispatchs periodically a 'progress' event holding the number of bytes already uploaded. If you need to stick with javascript, bridges are available between actionscript and javascript. The good news is that this work has been already done for you :)

swfupload

This library allows to register a javascript handler on the flash progress event.

This solution has the hudge advantage of not requiring aditionnal resources on the server side.


One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.


For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.

For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.


For the bytes uploaded it is quite easy. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.

For the bytes downloaded (when getting the info with xhr.responseText), it is a little bit more difficult, because the browser doesn't know how many bytes will be sent in the server request. The only thing that the browser knows in this case is the size of the bytes it is receiving.

There is a solution for this, it's sufficient to set a Content-Length header on the server script, in order to get the total size of the bytes the browser is going to receive.

For more go to https://developer.mozilla.org/en/Using_XMLHttpRequest .

Example: My server script reads a zip file (it takes 5 seconds):

$filesize=filesize('test.zip');

header("Content-Length: " . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.zip');
exit 0;

Now I can monitor the download process of the server script, because I know it's total length:

function updateProgress(evt) 
{
   if (evt.lengthComputable) 
   {  // evt.loaded the bytes the browser received
      // evt.total the total bytes set by the header
      // jQuery UI progress bar to show the progress on screen
     var percentComplete = (evt.loaded / evt.total) * 100;  
     $('#progressbar').progressbar( "option", "value", percentComplete );
   } 
}   
function sendreq(evt) 
{  
    var req = new XMLHttpRequest(); 
    $('#progressbar').progressbar();    
    req.onprogress = updateProgress;
    req.open('GET', 'test.php', true);  
    req.onreadystatechange = function (aEvt) {  
        if (req.readyState == 4) 
        {  
             //run any callback here
        }  
    };  
    req.send(); 
}

One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.



For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.

For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.


The only way to do that with pure javascript is to implement some kind of polling mechanism. You will need to send ajax requests at fixed intervals (each 5 seconds for example) to get the number of bytes received by the server.

A more efficient way would be to use flash. The flex component FileReference dispatchs periodically a 'progress' event holding the number of bytes already uploaded. If you need to stick with javascript, bridges are available between actionscript and javascript. The good news is that this work has been already done for you :)

swfupload

This library allows to register a javascript handler on the flash progress event.

This solution has the hudge advantage of not requiring aditionnal resources on the server side.



For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.

For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.


_x000D_
_x000D_
<!DOCTYPE html>_x000D_
<html>_x000D_
<body>_x000D_
<p id="demo">result</p>_x000D_
<button type="button" onclick="get_post_ajax();">Change Content</button>_x000D_
<script type="text/javascript">_x000D_
 function update_progress(e)_x000D_
 {_x000D_
   if (e.lengthComputable)_x000D_
   {_x000D_
     var percentage = Math.round((e.loaded/e.total)*100);_x000D_
     console.log("percent " + percentage + '%' );_x000D_
   }_x000D_
   else _x000D_
   {_x000D_
    console.log("Unable to compute progress information since the total size is unknown");_x000D_
   }_x000D_
 }_x000D_
 function transfer_complete(e){console.log("The transfer is complete.");}_x000D_
 function transfer_failed(e){console.log("An error occurred while transferring the file.");}_x000D_
 function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}_x000D_
 function get_post_ajax()_x000D_
 {_x000D_
    var xhttp;_x000D_
    if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers} _x000D_
   else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5    _x000D_
    xhttp.onprogress = update_progress;_x000D_
  xhttp.addEventListener("load", transfer_complete, false);_x000D_
  xhttp.addEventListener("error", transfer_failed, false);_x000D_
  xhttp.addEventListener("abort", transfer_canceled, false);    _x000D_
    xhttp.onreadystatechange = function()_x000D_
    {_x000D_
      if (xhttp.readyState == 4 && xhttp.status == 200)_x000D_
      {_x000D_
         document.getElementById("demo").innerHTML = xhttp.responseText;_x000D_
      }_x000D_
    };_x000D_
   xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);_x000D_
   xhttp.send();_x000D_
 }_x000D_
</script>_x000D_
</body>_x000D_
</html>
_x000D_
_x000D_
_x000D_

Result


If you have access to your apache install and trust third-party code, you can use the apache upload progress module (if you use apache; there's also a nginx upload progress module).

Otherwise, you'd have to write a script that you can hit out of band to request the status of the file (checking the filesize of the tmp file for instance).

There's some work going on in firefox 3 I believe to add upload progress support to the browser, but that's not going to get into all the browsers and be widely adopted for a while (more's the pity).


One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.


For the bytes uploaded it is quite easy. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.

For the bytes downloaded (when getting the info with xhr.responseText), it is a little bit more difficult, because the browser doesn't know how many bytes will be sent in the server request. The only thing that the browser knows in this case is the size of the bytes it is receiving.

There is a solution for this, it's sufficient to set a Content-Length header on the server script, in order to get the total size of the bytes the browser is going to receive.

For more go to https://developer.mozilla.org/en/Using_XMLHttpRequest .

Example: My server script reads a zip file (it takes 5 seconds):

$filesize=filesize('test.zip');

header("Content-Length: " . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.zip');
exit 0;

Now I can monitor the download process of the server script, because I know it's total length:

function updateProgress(evt) 
{
   if (evt.lengthComputable) 
   {  // evt.loaded the bytes the browser received
      // evt.total the total bytes set by the header
      // jQuery UI progress bar to show the progress on screen
     var percentComplete = (evt.loaded / evt.total) * 100;  
     $('#progressbar').progressbar( "option", "value", percentComplete );
   } 
}   
function sendreq(evt) 
{  
    var req = new XMLHttpRequest(); 
    $('#progressbar').progressbar();    
    req.onprogress = updateProgress;
    req.open('GET', 'test.php', true);  
    req.onreadystatechange = function (aEvt) {  
        if (req.readyState == 4) 
        {  
             //run any callback here
        }  
    };  
    req.send(); 
}

Firefox supports XHR download progress events.


One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.


If you have access to your apache install and trust third-party code, you can use the apache upload progress module (if you use apache; there's also a nginx upload progress module).

Otherwise, you'd have to write a script that you can hit out of band to request the status of the file (checking the filesize of the tmp file for instance).

There's some work going on in firefox 3 I believe to add upload progress support to the browser, but that's not going to get into all the browsers and be widely adopted for a while (more's the pity).


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to ajax

Getting all files in directory with ajax Cross-Origin Read Blocking (CORB) Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource Fetch API request timeout? How do I post form data with fetch api? Ajax LARAVEL 419 POST error Laravel 5.5 ajax call 419 (unknown status) How to allow CORS in react.js? Angular 2: How to access an HTTP response body? How to post a file from a form with Axios

Examples related to progress-bar

How to Create a circular progressbar in Android which rotates on it? Dynamically change bootstrap progress bar value when checkboxes checked Tkinter: How to use threads to preventing main event loop from "freezing" File upload progress bar with jQuery CSS Progress Circle How to set the Android progressbar's height? How to use WinForms progress bar? Display a loading bar before the entire page is loaded Progress Bar with HTML and CSS How to change color in circular progress bar?