XMLHttpRequest Level 2 - Determinate if upload finished
Solution 1
The event you want to listen to is readystatechange
on the XHR object (not on XHR.upload). readyState
is 4
when the upload has finished sending and the server closes the connection. loadend
/load
fire when the upload has finished regardless of whether the server closes the connection. Just for reference, here are the events you can listen to and when they fire:
var xhr = new XMLHttpRequest();
// ...
// do stuff with xhr
// ...
xhr.upload.addEventListener('loadstart', function(e) {
// When the request starts.
});
xhr.upload.addEventListener('progress', function(e) {
// While sending and loading data.
});
xhr.upload.addEventListener('load', function(e) {
// When the request has *successfully* completed.
// Even if the server hasn't responded that it finished.
});
xhr.upload.addEventListener('loadend', function(e) {
// When the request has completed (either in success or failure).
// Just like 'load', even if the server hasn't
// responded that it finished processing the request.
});
xhr.upload.addEventListener('error', function(e) {
// When the request has failed.
});
xhr.upload.addEventListener('abort', function(e) {
// When the request has been aborted.
// For instance, by invoking the abort() method.
});
xhr.upload.addEventListener('timeout', function(e) {
// When the author specified timeout has passed
// before the request could complete.
});
// notice that the event handler is on xhr and not xhr.upload
xhr.addEventListener('readystatechange', function(e) {
if( this.readyState === 4 ) {
// the transfer has completed and the server closed the connection.
}
});
Solution 2
Based on https://bugzilla.mozilla.org/show_bug.cgi?id=637002.
Let's go for a complete working example...
// YOUR (SIMPLE) JAVASCRIPT FILE
var form = new FormData(), xhr = new XMLHttpRequest();
form.append('inputname', YOURFILE);
xhr.open('POST', 'http://oneserver/onephpfile', true);
xhr.setRequestHeader('X-CSRF-Token', 'somestring');
xhr.onreadystatechange = function () {
if ((xhr.readyState === 4) && (xhr.status === 200))
// do other thing with xhr.responseText.trim()
};
xhr.upload.addEventListener('loadstart', showProgressBarFunction, false);
xhr.upload.addEventListener('progress', updateProgressBarFunction, false);
xhr.upload.addEventListener('load', updateProgressBarFunction, false);
xhr.send(form);
// YOUR FIRST (SIMPLE) PHP FILE
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');
sleep(20);
echo 'file processing ended';
With this first PHP file, you will see: 10%... 50%... 75%... 'do other thing' with Firefox (4/10/28/32) and IE (10/11). However you we will see: 10%... 50%... 75%... 100%... 'do other thing' with Chrome/Chromium (33/37) and Opera (24).
// YOUR SECOND (SIMPLE) PHP FILE
header('Content-Encoding: chunked', true);
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');
ini_set('output_buffering', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_clean();
echo ' ';
sleep(20);
echo 'file processing ended';
With this second PHP file, you will see: 10%... 50%... 75%... 100%... 'do other thing' with Chrome/Chromium (33/37/53), Opera (24/42), Firefox (4/10/28/32/45), IE (10/11) and Edge (14)!
Solution 3
This is a relatively known downfall of the hTML5 spec, when they could have easily extended it to add information such as timeRemaining and transferSpeed.
Have you considered using math.round
instead of math.ceil
for var percent
so that you are baking in a bit of fuzziness that would help get around a few % points being off?
You should also add another listener for loadComplete, if you are getting the UI stuck at <100% even though it is complete on the backend:
//only fires once
xhr.addEventListener('loadend', uploadComplete, false);
function uploadComplete(event) {
console.log('rejoice...for I have completed');
//do stuff
}
ninov
Updated on July 10, 2022Comments
-
ninov almost 2 years
I am using ajax for file uploads. After the file is uploaded, php should check it (mime, size, virus (clamscan) and more) - this takes some seconds for larger files. While the file is uploading, a HTML5
<progress>
is filling, when the file is ready and PHP starts checking, the progress should switch to indeterminate. I thought of to ways to do this (which both do not work):Checking upload.onload event
xhr.upload.addEventListener("load", function (e) { $("#uploadprogress").attr("value", false); $("#uploadprogress").attr("max", false); $("#progress").text("Checking file..."); });
This doesn't work, because the
onload
-event firest when the request is ready, not when upload is ready.Checking if upload progress percentage = 100%
xhr.upload.addEventListener("progress", function (e) { if (e.lengthComputable && e) { p = (e.loaded / e.total); if (p==1) { $("#uploadprogress").attr("value", false); $("#uploadprogress").attr("max", false); $("#progress").text("Checking file..."); } else { var percent = Math.ceil(p * 1000) / 10; $("#uploadprogress").val(e.loaded); $("#uploadprogress").attr("max", e.total); $("#progress").text("Uploading... " + percent + "%"); } } } });
This does not work, because the upload percentage sometimes stops at approx. 97%, despite the upload is finished and PHP starts handling the files
Is there another possibility checking this?
-
ninov about 11 yearsBut I don't want to check if the connection is closed, because after the upload is finished, PHP checks the file, which takes approx. 10 seconds and returns with some JSON. When PHP begins checking the file (=when upload is finished), the progress bar should switch to
indeterminated
-
zertosh about 11 yearswhen the file finishes transferring, the
loadend
/load
events fire, when your script finishes checking the file (which is when PHP closes the connection) thereadystatechange
event fires withreadyState===4
. so for your purposes, switch the progress bar toindeterminated
at thereadystatechange
event. see: gist.github.com/anonymous/5208652 -
ninov about 11 yearsDoesn't work. This is my JS: gist.github.com/anonymous/2a2fef447399a3b8e734 Imagine the PHP script is just
sleep(10);
. Now I want to show theindeterminated
progress bar for this 10 seconds -
zertosh about 11 yearsyou might have a browser issue. i just tested it (with some syntax fixes, etc.) on Chrome 25.0.1364.172 and 27.0.1449.0 and it works as expected. However, FF 19.0.2 is firing
load
/loadend
/readyState 4
simultaneously. -
ninov about 11 yearsWell, Firefox 19.0.2 is the browser I am using... I'll test with Chrome.
-
Gleno over 10 yearsMake sure to add the listener to the upload property and not xhr directly.