What is the difference between timeout and error in XMLHttpRequest? - javascript

Can somebody please explain me when error and ehen timeout error will be raised.
I put timeout here for PUT request but in what use case will be called onTimeout and in what onError handlers?
return new Promise(async function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open("PUT", url);
xhr.timeout = 10000;
xhr.onreadystatechange = async function() {
....
}
xhr.ontimeout = function() {
// Time out.
};
xhr.onerror = function() {
// Some error
};
}

The XMLHttpRequest.timeout property is an unsigned long representing the number of milliseconds a request can take before automatically being terminated. The default value is 0, which means there is no timeout. Timeout shouldn't be used for synchronous XMLHttpRequests requests used in a document environment or it will throw an InvalidAccessError exception. When a timeout happens, a timeout event is fired.
Despite the request timeout onerror method fires right after server has sent the error response. For example, if your server is shut down your timeout method will be fired after 10 seconds.
More info: here

Related

XHR throws timeout error and does not execute onTimeout event

I am coding a native JavaScript application in which I make simultaneous AJAX requests to multiple unique servers every minute. When a server is offline, I intended my program to handle this through the function registered to the XHR.ontimeout event.
Below is a quick JS sample I wrote to demonstrate my problem. Monitor the console and you will see only sometimes requests to an offline address trigger the ontimeout event. Other times ERR_CONNECTION_TIMED_OUT occurs. I would like to have a timeout handler that executes every time I call my function and the server is offline.
<!DOCTYPE html>
<html>
<TITLE>Timeout Error Demo</TITLE>
<body>
<script>
var i=0;
var xhr;
function main(){
console.log('Main run #'+i);
i++;
xhr=new XMLHttpRequest();
xhr.open("GET", "http://1.1.1.1", true); //this address is always offline
xhr.timeout=2000;
xhr.ontimeout=function(){
console.log("timed out");
}
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200){
console.log("done");
}
}
xhr.send(null);
setTimeout(main,5000);
}
main();
</script>
</body>
</html>
As i see it the core of the problem here is that you misunderstand how the ontimeout event works. So i will try to explain how the browser works with ontimeout and what the difference is with onerror.
ontimeout
The ontimeout event will to thrown when a request is made to the server and that request get succesfully through to the server. Then if the server takes a long time to response the timeout event will get thrown by the HTTPRequest.
Ex:
Client side
xhr.timeout = 2000;
xhr.send();
xhr.open("GET", /somecontroller/IAmAReallySlowEndpoint, true);
xhr.ontimeout = function() {
console.log("I get called because the server was to slow to response on a succesfull request");
}
Server side endpoint (C#)
public bool IAmAReallySlowEndpoint()
{
Thread.Sleep(4000);
return true;
}
you call a server side endpoint which does not answer within 2 seconds then the ontimeout event will get thrown.
onerror
The onerror event will throw if an error in the http request happens which is the case in your example. You want to call an url that is down. Calling an url that is down will throw an error and thereby the onerror event is called.
So when you write that it works when do you:
xhr.ontimeout = xhr.onerror
You are just passing the onerror event to the ontimeout.
So to solve your problem with doing stuff if one of the endpoints you are requesting is down you should implement some retry logic kinda like you already have with a setTimeout() but deciding if the server is down or not should be based on numbers of failed request to the server instead of the ontimeout.
It's .ontimeout, not .onTimeout. Or .addEventListener("timeout", …).

Why this image access loading error on a Promise script fiddle?

I'm using a Promise to load an image in a fiddle and keep getting an access error. I've tried a variety of images - posted to dropbox, placeholders, and others, but all are blocked. What can I use/do that will work? I believe the question and answer here are relevant, but am having trouble connecting the dots.
Here is the error:
XMLHttpRequest cannot load https://www.dropbox.com/s/i7ptcure9tlw8pl/Pensive%20Parakeet.jpg?dl=0. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.
I'm using the fiddle to practice writing Promises to get my head around them, and have borrowed the script here to practice on. My fiddle in question is here.
As I explained in my comment that URL from dropbox doesn't allow cross-origin requests plus the resource isn't an image (it's actually html). If you use images from a site that allows cross-origin requests (like imgur for example) then it works.
function imgLoad(url) {
// Create new promise with the Promise() constructor;
// This has as its argument a function
// with two parameters, resolve and reject
return new Promise(function(resolve, reject) {
// Standard XHR to load an image
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = 'blob';
// When the request loads, check whether it was successful
request.onload = function() {
if (request.status === 200) {
// If successful, resolve the promise by passing back the request response
resolve(request.response);
} else {
// If it fails, reject the promise with a error message
reject(Error('Image didn\'t load successfully; error code:' + request.statusText));
}
};
request.onerror = function() {
// Also deal with the case when the entire request fails to begin with
// This is probably a network error, so reject the promise with an appropriate message
reject(Error('There was a network error.'));
};
// Send the request
request.send();
});
}
// Get a reference to the body element, and create a new image object
var body = document.querySelector('body');
var myImage = new Image();
// Call the function with the URL we want to load, but then chain the
// promise then() method on to the end of it. This contains two callbacks
imgLoad('https://i.imgur.com/Kusegys.jpg').then(function(response) {
// The first runs when the promise resolves, with the request.reponse
// specified within the resolve() method.
var imageURL = window.URL.createObjectURL(response);
myImage.src = imageURL;
body.appendChild(myImage);
// The second runs when the promise
// is rejected, and logs the Error specified with the reject() method.
}, function(Error) {
console.log(Error);
});
img {
height:1125px;
width:750px;
}

On slow network previous Ajax request gets cancelled by the subsequent

I have the following problem:
I'm trying to send two Ajax requests almosts simulateously:
function ajax()
{
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
console.log(xhr.responseText);
}
xhr.open('GET', 'list.html', true);
xhr.send('');
}
ajax();
ajax();
The problem is that only one of them succeeds.
And if I try in the DevTools my self, if the network speed is high, they get both executed (when I quickly type the ajax() function twice in the console) while if I lower the network speed and again type them quickly only one of them succeeds.
Why is this happening? How can I avoid this auto canceling of simultaneous xhr requests?
You should use a local variable to hold the XMLHttpRequest. Since you're using a global variable, the callback function always refers to the second AJAX request that was sent. So change:
xhr = new XMLHttpRequest();
to:
var xhr = new XMLHttpRequest();
Then each callback funtion will be a closure that refers to that specific request that was sent.

Check if ajax was aborted

I am not using jquery (cause I cant in this specific project) so how do I know the request was aborted by user using .abort() method? I read a lot and there is no abort method in the object XMLHttpRequest.
I know I can chek the status and readyStatus of onreadystatechange but it does not tell me anything if the connection was aborted
thans.
You can determine if the request has been aborted by testing the readyState, which will again be 0.
var xhr = new XMLHttpRequest();
console.log(xhr.readyState); // 0
xhr.open('GET', '/');
console.log(xhr.readyState); // 1
xhr.abort();
console.log(xhr.readyState); // 0
If you need to know when it's aborted, not just if, then you'll have to use onabort as onreadystatechange won't be triggered by it.
var xhr = new XMLHttpRequest();
xhr.onabort = function () {
console.log('Was aborted', xhr.readyState);
};
xhr.open('GET', '/');
xhr.send();
xhr.abort(); // Was aborted 0

Polling from a JavaScript worker using XMLHTTPRequest

I’m trying to create a worker that does the following simultaneously:
Sends an XMLHTTPRequest to a server to perform a task (which may
take a long time)
Sends an XML HTTP Request Message every X seconds to get an update on the process until the process (1) is complete.
What i have so far is below. But it doesnt poll. The first part is successfully executed. The second bit runs just once. Does anyone know what i'm doing wrong?
onmessage = function (e) {
e.data.params.task = "runTask"; // The server understands this. This performs(1)
// Sends an asynchronous request to perform (1)
var xhr = new XMLHttpRequest();
xhr.open('POST', e.data.url, false);
xhr.setRequestHeader("Content-type", "application/json");
xhr.send(JSON.stringify(e.data.params));
// initialise polling
var interval = 500;
// Poll until (1) is complete
(function poll(){
if (xhr.readyState != 4){ // while (1) is yet to be completed..
e.data.params.task = "getProgress";
// Send another request to the server to get an update on the first process
var pollxhr = new XMLHttpRequest();
pollxhr.open('POST', e.data.url, true);
pollxhr.setRequestHeader("Content-type", "application/json");
pollxhr.timeout = interval;
pollxhr.ontimeout = poll; // This should cause the process to poll
pollxhr.onreadystatechange = function(){
e.data.progress = pollxhr.responseText;
postMessage(e.data);
};
pollxhr.send(JSON.stringify(e.data.params));
}else{
e.data = xhr.responseText;
postMessage(e.data);
}
})();
};
The problem is with the first call
xhr.open('POST', e.data.url, false);
^^^^^
Looking at the method you can see the third parameter is async
open(DOMString method, DOMString url, optional boolean async, optional DOMString? user, optional DOMString? password);
By setting it to false, you are telling it to run synchronously, which means nothing else will happen until it the call is returned. That results in your polling code running after the first call is returned. Set it to run asynchronously and use the onreadystatechange to get when it is completed!

Categories

Resources