How to detect timeout on an AJAX (XmlHttpRequest) call in the browser? - javascript

I'm looking on the web, but documentation is hard to come by. We all know the basic AJAX call using the browser's built-in XMLHttpRequest object (assume a modern browser here):
var xmlHttp = new XMLHttpRequest(); // Assumes native object
xmlHttp.open("GET", "http://www.example.com", false);
xmlHttp.send("");
var statusCode = xmlHttp.status;
// Process it, and I'd love to know if the request timed out
So, is there a way that I can detect that the AJAX call timed out by inspecting the XMLHttpRequest object in the browser? Would I be advised to do something like window.setTimeout(function() { xmlHttp.abort() }, 30000);?
Thanks!
-Mike

Some of the modern browsers (2012) do this without having to rely on setTimeout: it's included in the XMLHttpRequest. See answer https://stackoverflow.com/a/4958782/698168:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
alert("ready state = 4");
}
};
xhr.open("POST", "http://www.service.org/myService.svc/Method", true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.timeout = 4000;
xhr.ontimeout = function () { alert("Timed out!!!"); }
xhr.send(json);

UPDATE: Here's an example of how you can handle a timeout:
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", "http://www.example.com", true);
xmlHttp.onreadystatechange=function(){
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
clearTimeout(xmlHttpTimeout);
alert(xmlHttp.responseText);
}
}
// Now that we're ready to handle the response, we can make the request
xmlHttp.send("");
// Timeout to abort in 5 seconds
var xmlHttpTimeout=setTimeout(ajaxTimeout,5000);
function ajaxTimeout(){
xmlHttp.abort();
alert("Request timed out");
}
In IE8, You can add a timeout event handler to the XMLHttpRequest object.
var xmlHttp = new XMLHttpRequest();
xmlHttp.ontimeout = function(){
alert("request timed out");
}
I would recommend against making synchronous calls as your code implies and also recommend using a javascript framework to do this. jQuery is the most popular one. It makes your code more efficient, easier to maintain and cross-browser compatible.

Related

XmlHttprequest : How do not let the server wait for the next request

I want to ask the server to get the data.
The data comes in normally, but it takes a lot of time.
What I want to do is send xmlhttpRequest.send (null) from Client side, send response data fastly from server side.
i checked the server side log to solve time-consuming problem, and found that:
Even after receiving xmlhttpRequest.send (null) it waits for the next request and eventually times out.
i wonder if this is a server-side problem or a client-side problem using xmlhttprequest.
Client-side code
function HomeLoad() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/HomeLoad.asp', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
if(xhr.status == 200){
//home_Arr = xhr.responseText.split('&');
}
}
};
xhr.send(null);
}
$(document).ready(function()
{
HomeLoad();
});
Synchronous XHR requests often cause hangs on the web. But developers typically don't notice the problem because the hang only manifests with poor network conditions or when the remote server is slow to respond. Synchronous XHR is now in deprecation state. The recommendation is that developers move away from the synchronous API and use synchronous requests.
For more information refer below URL:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
var request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false); // `false` makes the request synchronous
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
For Asynchronous Request:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/bar/foo.txt", true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
Line 2 specifies true for its third parameter to indicate that the request should be handled asynchronously.

Close specific XMLHttpRequest

How to "rebuild" function to close specific XMLHttpRequest? I have defined variable outside function to call xhr.abort(); everywhere I need. Now is possible, with this solution, close last running XMLHttpRequest if running more than one at same time - processes before last running are without control after replace xhr by re-calling _ajax()
var xhr;
function _ajax(data, callback) {
xhr = new XMLHttpRequest();
xhr.open('POST', window.location.pathname, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this);
}
};
xhr.send(data);
}
/* close fnc */
xhr.abort();
You could use xhr as an array and store there all the requests; then you can call abort on any one of them. Like:
var xhr=[];
function _ajax(data, callback) {
xhr.push(new XMLHpptRequest);
//etc
}
xhr[0].abort();
xhr.shift(); //get rid of the aborted request

Can't access page using xmlhttprequest

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.

javascript: wait for a return

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.");
}
}
};
}

XMLHttpRequest object not being instantiated?

I'm new to Ajax and this has me stumped. It's relatively simple but trips up on the onclick handler with the first xhr.open(). Firebug says it's not a function, my guess is the XMLHttpRequest object isn't being created, but I'm not sure. Anyone have any ideas?
Thanks in advance.
function init(){
function getXMLHTTP(){
var xhr = false;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
function updatePage(theData){
$('results').innerHTML = theData; //TODO: pretty this up with mootools
}
var xhr = getXMLHTTP();
if (xhr) {
xhr.onreadystatechange = function(){
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var theData = xhr.responseText;
updatePage(theData);
}
else{
alert("Error communicating to web service!");
}
}
}
$('submit_btn').onclick = function(xhr){
if ($('state').value != "") {
var theValue = $('state').value;
xhr.open("GET", "/inc/calc.php?state="+theValue, true); //Ajax 101: 3rd argument marks object as asynchronous
xhr.send(NULL);
}
else if ($('city').value != "") {
xhr.open("GET", "/inc/calc.php?city="+$('city').value, true);
xhr.send(NULL);
}
else if ($('county').value != "") {
xhr.open("GET", "/inc/calc.php?county="+$('county').value, true);
xhr.send(NULL);
}
else {
//the form is empty, or just down payment is filled. returns whole freakin' table.
xhr.open("GET", "/inc/calc.php", true);
xhr.send(NULL);
}
}
}
}
The problem with your code is the onclick function. You have put the xhr in the argument list to the function. Remember that when a function is called, the value of this variable is set by the caller. In this case it would be the event dispatcher, and it would probably set the xhr variable to an event object, which does not have an open function.
If you remove the xhr variable from the argument list of the onclick function, then it will look for the xhr variable in the parent scope, the global scope, and it will find it there, and it should work. I haven't tested it though.
I'm assuming you are using some kind of framework as well (judging by the frequent use of $, and the reference to mootools). This framework probably has an ajax function built in, as well as a cross browser event model. Try using it instead, you will run into a lot less problems.
When assigning the onclick handler you create a new function that takes a parameter called xhr:
$('submit_btn').onclick = function(xhr){
...
xhr.open("GET", "/inc/calc.php?state="+theValue, true);
...
}
The click on the button won't pass a XMLHttpRequest object the the handler, so xhr will not have an open() method. The global definition of xhr doesn't matter because it's shadowed by the local parameter definition.
Generally you should just generate a new local XMLHttpRequest object when you need it, not try to use a global one. For example use an onclick function that creates a new local XMLHttpRequest:
$('submit_btn').onclick = function(){
var xhr = getXMLHTTP();
xhr.open("GET", "/inc/calc.php?state="+theValue, true);
...
}

Categories

Resources