I have this function for sending data to my (localhost) server. However, when Wamp was accidentally stopped (localhost server down) I noticed that timeout is not working properly.
If I set the timeout to 2000 mS, the callback is called normally like is supposed. If I set to 4000 mS, the timeout is never called. Instead, readystate will reach 4 (DONE) but with no meaning HTTP status (zero?).
The debug is as follows:
READY STATE: 2 STATUS: 0
READY STATE: 4 STATUS: 0
This is normal or do I miss something here?
I use Firefox latest, 53. Thanks.
function ServerSend(url) {
var xhr = new XMLHttpRequest();
// In Internet Explorer, the timeout property may be set only after calling the open() method and before calling
// the send() method.
xhr.open("GET", url, true);
xhr.timeout = 4000;
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
ShowInfo(xhr.responseText)
}
// DEBUG
{
console.log("READY STATE: "+xhr.readyState+" STATUS: "+xhr.status);
}
};
xhr.ontimeout = function () {
xhr.abort();
alert("Timed out!!!");
//ShowInfo("Server timeout");
};
xhr.send();
}
Related
I have an xmlhttprequest code that is executed on a button, it runs and access the advReqPage.aspx on the first run but when I press the button again, it doesn't access the advReqPage.aspx any more. What is the problem here?
function SaveAdvPayment() {
var xhr = new XMLHttpRequest();
var ornumber = document.getElementById("ORNumber").value;
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 200) {
// OK
alert('response:' + xhr.responseText);
// here you can use the result (cli.responseText)
} else {
// not OK
alert('failure!');
}
}
}
xhr.open("GET", "Server_Requests/advReqPage.aspx?poo=" + ornumber + "&sess=INSERT", false);
xhr.send();
alert('Saved');
$('#myModal').modal('hide');
}
Probably the first response is getting cached and when you make the second request your browser is not making this new request. This behavior is due to browser locking the cache and waiting to see the result of one request before requesting the same resource again. You can overcome this by making your requests unique like adding random query string.
Background
I am making a request every 5 seconds using XMLHttpRequest and I want to print my name when I receive the response.
To do this I am using onreadystatechange which allows me to define a callback function when I receive the answer.
Problem
To achieve this, I am using a class. When I first initiate the class I say my name immediately, and then I start a process using setTimeInterval to make a request every 5 seconds and see my name.
The problem is that I see my name the first time, but then I never see it again. The issue is that this seems to be in different context, and thus this.sayMyName() doesn't exist because it doesn't belong to the xhr object.
What I tried
To fix this I tried using scoping by following another StackOverflow question but unfortunately this remains undefined.
Code
class Cook {
constructor() {
// innitial call so we don't have to wait
//5 seconds until we see my name
this.getCookInfo();
setInterval(this.getCookInfo, 5000);
}
getCookInfo() {
var xhr = new XMLHttpRequest(),
method = "GET",
url = "https://best.cooks.in.the.world.org/";
xhr.open(method, url, true);
//Call a function when the state changes.
xhr.onreadystatechange = (self => {
return () => {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200)
self.sayMyName();
};
})(this);
}
sayMyName() {
console.log("Heisenberg");
}
}
Questions:
Is there a way to fix this code without have to pass a context object to the setInterval function?
Note
Kudos++ for those of you who get my reference :P
bind the this.getCookInfo function to this
then you can rally simplify your code
class Cook {
constructor() {
// innitial call so we don't have to wait
//5 seconds until we see my name
this.getCookInfo();
setInterval(this.getCookInfo.bind(this), 5000);
}
getCookInfo() {
var xhr = new XMLHttpRequest(),
method = "GET",
url = "https://best.cooks.in.the.world.org/";
xhr.open(method, url, true);
//Call a function when the state changes.
// no need for self gymnastics any more
// using onload, no need to test reasyState either
xhr.onload = e => {
if (xhr.status == 200)
this.sayMyName();
};
// your code lacks one thing
xhr.send();
}
sayMyName() {
console.log("Heisenberg");
}
}
An alternative -
class Cook {
constructor() {
this.getCookInfo();
}
getCookInfo() {
var getit = () => {
var xhr = new XMLHttpRequest(),
method = "GET",
url = "https://best.cooks.in.the.world.org/";
xhr.open(method, url, true);
//Call a function when the state changes.
xhr.onload = e => {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200)
this.sayMyName();
};
xhr.send();
};
getit();
setInterval(getit, 5000);
}
sayMyName() {
console.log("Heisenberg");
}
}
I'm only 99% sure this is right though :p
I'm making a call to an API and then trying to render a chart of the data returned:
function getFromAPI(url) {
return new Promise( (resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log("Resolving!");
jsonData = JSON.parse(xhr.responseText);
resolve(jsonData);
} else {
console.log("Rejecting!");
reject();
}
}
xhr.open("GET", url, true);
xhr.send();
});
}
getFromAPI(API_URL).then( (jsonData) => { drawChart(jsonData) });
When I load that script I get Rejecting! three times in the console before it resolves. The reject is also breaking the .then part (i.e. no chart for me!)
I take it the onreadstatechange event is firing a few times before we get to readyState == 4 and status == 200. What exactly is going on and how do I avoid rejecting the promise prematurely?
The onreadystatechange is an event handler that is fired whenever the xhr readyState changes.
0 UNSENT Client has been created. open() not called yet.
1 OPENED open() has been called.
2 HEADERS_RECEIVED send() has been called, and headers and status are available.
3 LOADING Downloading; responseText holds partial data.
4 DONE The operation is complete.
As you can see there are 4 "not ready" states, and one "done". This accounts for the console log of reject and resolve that you see.
When the request is "done", reject or resolve the request according to the status:
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
console.log("Resolving!");
jsonData = JSON.parse(xhr.responseText);
resolve(jsonData);
return;
}
console.log("Rejecting!");
reject();
}
I have this problem.
I have a function for example called functionA() that needs the results from another function called functionB().
var globalVar="";
function functionA(){
//...
functionB();
//here i have to use the global variable (that is empty because functionB isn't finished)
}
function functionB(){
//ajax request
globalVar=ajaxRequest.responseText;
}
How can I do to let the functionB finish befor continue with the execution of functionA?
Thanks!
This is the code:
var ingredientiEsistenti="";
function ShowInserisciCommerciale() {
getElementiEsistenti();
JSON.parse(ingredientiEsistenti);
}
function getElementiEsistenti(){
// prendo gli ingredienti esistenti.
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
ingredientiEsistenti = xmlHttp.responseText;
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}
You've got one of many options, that don't require an evil global variable:
Move the code you want to see executed to the onreadystatechange callback of the ajax request, that way, it won't get executed until you received a response
Redefine functionA, so that it takes a parameter that allows you to skip the first bit:
Make the request synchronous, not recommended, though
use a timeout/interval to check the readystate of the request manually (brute-force, not recommended either)
Perhaps there is some worker trickery that could do the trick, too, in your particular case
function functionA(skipDown)
{
skipDown = skipDown || false;
if (skipDown === false)
{
//doStuff
return functionB();//<-- call functionA(true); from the readystatechange callback
}
//this code will only be called if skipDown was passed
}
It is impossible to have a sleep/wait in JavaScript when the call is asynchronous. You need to use a callback pattern to make this action occur.
It is possible to make an XMLHttpRequest synchronous, but that can lead to other problems. It can hang the browser as it blocks all other actions from happening. So if you want to show a loading animation, it most likely will not execute.
You can make your AJAX request synchronous. https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
var request = new XMLHttpRequest();
// Last parameter makes it not asnychronous
request.open('GET', 'http://www.mozilla.org/', false);
request.send(null);
// Won't get here until the network call finishes
if (request.status === 200) {
console.log(request.responseText);
}
However, that will block the UI while waiting for the server to respond, which is almost never what you want. In that case, you should use a callback to process results.
Here's an example using a callback without relying on a global variable. You should always run away from those
function ShowInserisciCommerciale( ) {
getElementiEsistenti(function(responseText) {
JSON.parse(responseText);
});
}
function getElementiEsistenti(successCallback){
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
successCallback(xmlHttp.responseText);
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}
I'm writing an AIR application that communicates with a server via XmlHttpRequest.
The problem that I'm having is that if the server is unreachable, my asynchronous XmlHttpRequest never seems to fail. My onreadystatechange handler detects the OPENED state, but nothing else.
Is there a way to make the XmlHttpRequest time out?
Do I have to do something silly like using setTimeout() to wait a while then abort() if the connection isn't established?
Edit:
Found this, but in my testing, wrapping my xmlhttprequest.send() in a try/catch block or setting a value on xmlhttprequest.timeout (or TimeOut or timeOut) doesn't have any affect.
With AIR, as with XHR elsewhere, you have to set a timer in JavaScript to detect connection timeouts.
var xhReq = createXMLHttpRequest();
xhReq.open("get", "infiniteLoop.phtml", true); // Server stuck in a loop.
var requestTimer = setTimeout(function() {
xhReq.abort();
// Handle timeout situation, e.g. Retry or inform user.
}, MAXIMUM_WAITING_TIME);
xhReq.onreadystatechange = function() {
if (xhReq.readyState != 4) { return; }
clearTimeout(requestTimer);
if (xhReq.status != 200) {
// Handle error, e.g. Display error message on page
return;
}
var serverResponse = xhReq.responseText;
};
Source
XMLHttpRequest timeout and ontimeout is a-syncronic and should be implemented in js client with callbacks :
Example:
function isUrlAvailable(callback, error) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
return callback();
}
else {
setTimeout(function () {
return error();
}, 8000);
}
};
xhttp.open('GET', siteAddress, true);
xhttp.send();
}