Usually I always find a solution to my questions on stackoverflow, you guys are really great! But after hours and hours of searching I am still stuck with this problem:
I am programming a browser extension for Chrome/FF which uploads a file to a server via xhr post method. If the server is not responding I want to give the user a feedback that the connection timed out. Therefore first I used a timeout value of 10000 ms because I thought that the timeout only starts counting after the request/file has been completely sent. However, it turned out that on slow connections the upload took more than 10 sec and the timeout event was fired before the file was sent completely. For some larger files the upload took even some minutes and hence I had to set the timeout value up to 5 min. This is however unpractical on fast connections. On fast connections I do not want to wait 5 min before I can inform the user that the connection timed out if the server was not responding.
Hence I am looking for a xhr solution which should:
Is there any possibility to achieve this?
Edit: What I tried so far was:
[...]
var originalTimeout = 10000;
xhr.timeout = originalTimeout;
[...]
xhr.upload.addEventListener('loadstart', function(e) {
xhr.timeout = 600000;
});
xhr.upload.addEventListener('loadend', function(e) {
xhr.timeout = originalTimeout;
});
I did several upload tests and like this obviously the timeout value was changed to 600000 by the upload-'loadstart' event listener because sending the file took usually much more then 10 sec and no timeout event was fired. But thereafter always a timeout event was fired immediately after the file was completely sent to the server. I was able to confirm on the server side that the file was received completely and also the the response was sent. However, the response was not received by the script as the timeout event was fired before.
Any idea would be really appreciated!
You can use a Promise
, specifically the Promise.race
method, along with the XMLHttpRequestUpload
object. You can have one promise be a timer, and the other waiting for the XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.timeout = (1000 * 60) * 5 //5 minute initial timeout timer.
xhr.ontimeout = function() {
doSomething(); //if 5 minute timeout is done.
};
var xhrUpload = xhr.upload;
xhrUpload.loadend = function() { //when upload is done, move on to 10s server timer.
raceThis(xhr, callback)
}
xhr.open('METHOD', url, true);
function raceThis(xmlReq, callback) {
var waitForServer = new Promise(function(resolve, reject) {
xmlReq.onreadystatechange = function() {
if(xmlReq.readyState = 2) {
resolve(false); //the moment HTTP headers are sent as a response, resolve
}
}
})
var waitFor10Seconds = new Promise(function(resolve, reject) {
window.setTimeOut(function() {
resolve(true)
}, 10000)
})
Promise.race([waitForServer(), waitFor10Seconds()])
.then(function(serverTimedOut) {
if(serverTimedOut) {
//do stuff if the server timed out
} else {
//do stuff if the server didnt time out
};
callback(serverTimedOut) //you can even use dedicated callbacks!
})
}
This is a crude representation, there are many ways to expand on this but this is the main idea.