views:

857

answers:

2

I work on a JScript/VBScript HTML application (so we can execute at higher privileges than a normal web page) and we're providing the capability to download a file and need to provide feedback on the download progress to our users. Naturally, I figured a progress bar or progress text based on the total file size and the amount of the file already downloaded. I'm trying to get the size of the already downloaded portion in Internet Explorer. Thus far, I've tried everything I can think of to access how much of the file is already downloaded. When trying to access the responseText or responseBody during readyState 3 (interactive), I simply get the exception:

The data necessary to complete this operation is not yet available.

So it appears that Microsoft was not lying when they documented that responseText or responseBody will not be available until the XMLHttpRequest has completed (gone to readyState 4)

I can get the total file size and save the file to disk, so I've omitted those parts of the code I already have. Here's what I've been trying. I'm open to any other suggestions -- even changing implementations away from XMLHttpRequest. Note that I do not have control over the server side of things... only my client app, so php/ASP solutions won't work. Thanks in advance...

function getRemoteFile(urlToFile){
  if (urlToFile)    {
    try      {
      var xmlReq = new XMLHttpRequest();
      //Tried all of the following with no luck
    //var xmlReq = new ActiveXObject('Microsoft.XMLHTTP');
    //var xmlReq = new ActiveXObject('Msxml2.DOMDocument.3.0');
    //var xmlReq = new ActiveXObject("Msxml2.XMLHTTP.3.0");
    //var xmlReq = new ActiveXObject("Msxml2.XMLHTTP.6.0");
    //var xmlReq =new ActiveXObject("Msxml2.DOMDocument.6.0");

      function updateDownloadProgress() {                     
        if (xmlReq.readyState == 3) {
            try {
              alert(xmlReq.responseText.length);

            }
            catch (e) {
            alert(e.message);
            }          
          window.setTimeout(updateDownloadProgress, 200);
        }
      }                    

      xmlReq.open("GET", urlToFile, true);
      xmlReq.onreadystatechange = function(){
        if (xmlReq.readyState == 3)      {
          updateDownloadProgress();
        }
        if (xmlReq.readyState == 4)      {
          alert("done");
        }
      }
      xmlReq.send(null);
    } catch(e) {
      alert(e.message);
      return null;
    }
  }
}
A: 

Add a try/catch block when you check for download progress. Make sure you flush the data when available from the server, some servers/server-scripting will buffer the content.

bucabay
I don't see exactly how that'll help - even if the data is flushed, on a multi-MB download you don't usually get reliable progress indicators for the download. Can you elaborate? Thanks.
Vinay Sajip
A: 

I don't think you can do this straightforwardly, because you won't get progress updates on the client side (at least, not in a neat cross-browser fashion) until everything has been received. However, you can tell on the server side how much of the file you have written to the response. So one approach is to make the amount written to the response for a particular download request available in parallel via a second AJAX call. So, give each download an ID, store the download state server-side findable by this ID, and invoke separate, parallel AJAX requests to query the progress for that ID. Then display that in whatever way you want - progress bar, label showing percentage completion, etc.

See this post for a discussion of the issues around readyState == 3.

Vinay Sajip