I have a function in a .js file that takes information stored in localStorage and syncs them back to the server using synchronous ajax calls. (Order of integration is vital, hence synchronous is necessary)
function syncUp() {
var xml = new XMLHttpRequest();
xml.open("GET", "Default.aspx", true); Also tried setting this to false
xml.onreadystatechange = function() {
if (xml.readyState == 4) {
if (xml.status == 200) {
var items = localStorage.getItem("SyncOrder");
var sync = items.split(",");
for (var i = 0; i < sync.length -1; i++) {
Perform repeated synchronous calls to webservice via AJAX to integrate each item to the server
}
}
}
}
xml.send(null);
}
syncUp() is being called from more than one place. When called directly from the onclick event of a button where syncUp() is the only function called and the only code running, it works great. However, if from a page where I am first adding an item to the localStorage object and then calling syncUp() as follows
function saveEdit(item) {
var currData = localStorage.getItem("SyncOrder");
localStorage["SyncOrder"] = currData + "," + item;
syncUp();
}
, the xmlHTTPRequest status returns 0 and the sync doesn't perform. What could possibly be preventing the xmlHTTPRequest from getting a response of 200 as the only code running before syncUp() is a couple lines of javascript, which should be done executing before the site even gets into syncUp()?
There are two causes of status code of zero.
Making calls from the file protocol.
The page is refreshing/navigating away as the request is being made.
In your case I would assume it is #2. If you are using a button or a link to make the Ajax call, make sure to cancel the click action with either preventDefault or return false.
Related
I am developing a web-application on File Management System in which I have to access various directories on my system and list them on my web page. I have used AJAX to make rest calls to the server. I have created a rest-controller to handle the requests.
I am encountering a problem in the execution of a java-script function which I have to call recursively on the basis of a counter. The function is to navigate backwards in a directory. If the value of count is zero, I will display the result on the web page, else I will recursively call the function. The function works as expected in Chrome but not in IE-11.
I want to make multiple calls to the server based on the counter value. Hence I am calling the function recursively, but the call to the server is made only once. This problem occurs in IE-11. In Chrome, it works perfectly.
The function is:
function gobackDir(count) {
var back_count = count;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","http://neha:8080/myServer/goback",true);
xmlhttp.send();
xmlhttp.onreadystatechange=function($event) {
if ($event.currentTarget.readyState==4 && $event.currentTarget.status==200) {
back_count--;
if (back_count > 0) {
gobackDir(back_count);
}
else {
var server_response = JSON.parse($event.currentTarget.response);
set_currentDirectory(server_response);
set_directoryContent(server_response);
}
}
}
}
In IE, you need to bust the cache:
var bustCache = (new Date()).getTime();
xmlhttp.open("GET","http://neha:8080/myServer/goback?" + bustCache,true);
In this discussion and in chat I understood that a callback is the only way to go!
"
Get from the server a link with ajax, write the link in a variable, open an xml with this link, doing some stuff with the xml: is callback the only way?
"
I'm trying to understand what a callback is. I read some blog, but I still have problems.
What I have now in JS is
1) a function to open an xml.
2) function to request the link of the xml in first function
Can someone provide an example in PLAIN JAVASCRIPT of how to nest these two functions?
The server generate the link of the xml because I'm making a multi user web site and every user has it's own xml. So I need to ask the server what is the link of the xml and then open it. Is there an easy way to achieve this? I need plain javascript no jquery.
Thanks!
In general, a "callback" is a function which will be executed at a later time when an asynchronous process is completed.
So you might start by defining the function that should happen when the data is retrieved from the server (the "second" function, intuitively, but you should define it first because it's the business functionality you're looking to achieve and not just an implementation concern). Something as simple as:
var doSomethingWithTheData = function () {
// do, well, something with the data
};
This assumes that you have the data, which you don't yet. But the AJAX call will get that data. You can now use this function as your callback for the AJAX call. Taking the AJAX example from MDN, you might have this:
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.onreadystatechange = doSomethingWithTheData;
// perform the AJAX request
The httpRequest object will contain the response from the server after the AJAX call is executed and completed. (Remember that this happens asynchronously, so it won't contain the response on the immediate next line of code. It will at some later time which you don't control. Hence the need for the callback.)
I recommend walking through that full MDN article to get all the details, particularly on handling errors and such. But the data you're looking for (assuming nothing went wrong) would be in httpRequest.ResponseText. So, also assuming your variables are scoped to allow this (you can modify that as needed):
var doSomethingWithTheData = function () {
var data = httpRequest.ResponseText;
// do, well, something with the data
};
Excuse me, #David
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari,
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://myserver.mydomain/getMyUsersXMLUrl?user=pete";
httpRequest.open("GET", url, true); // next ajax to retrieve XML - File
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState == 4) { // response received
var response = httpRequest.responseText; // this should contain you url
httpRequest.open("GET", response, true); // next ajax to retrieve XML - File
// and the same as for the first request
}
}
If You just need to download a xml you dont need a callback . Just take a look at jquery and ajax. Retrieving a callback from a server is not possible . JSONP does deal with callbacks that are called by the server (actually they arent ) Butter you wont need it. I think you are messaging the xhttprequestobject
A callback function is simply a piece of executable code passed as a parameter to another piece of code. For example:
function first (arr, predicate) {
// no predicate supplied, return first element
if (!predicate) return arr[0];
for (var i = 0; i < arr.length; i++) {
// return first element satisfying predicate
if (predicate(arr[i])) return arr[i];
}
// no element satisfying predicate, return null
return null;
}
// second parameter is an anonymous function
// will alert 4, as it's the first element which will return true
alert(first([1, 2, 3, 4, 5, 6], function(n) { return n > 3; }));
Callbacks are useful for asynchronous tasks, or for library functions which need extra customization at runtime.
Once the JSP is rendered, I'm here trying to make an Asynchronous call via ajax to load additional information on the page.
I'm expecting that ajax load to happen gracefully without hampering the UI scroll bar navigation. But the call blocks the UI until the onLoad is complete.
At other times, this service blocks UI even on a mouse click ajax call (the cursor remains as pointer type until data is loaded).
In both cases, I'm building DOM via javascript (like creating innerHTMl for a div or table). Is it because of this? or something else? I'm attaching my ajax request code.
Appreciate your help. (Sorry, I tried to format the code, but I'm unable to get it right here)
function requestService(theService, theParamObj, isSyncCall) {
var ajaxRequest = getAjaxRequest();
var params = "data=";
if(theParamObj != null)
params += encodeURIComponent(JSON.stringify(theParamObj));
ajaxRequest.onreadystatechange = function() {
if (ajaxRequest.readyState == 1) {
showLoadingBox();
}
if (ajaxRequest.readyState == 4) {
handleResponse(ajaxRequest.responseText, theService, theParamObj);
hideLoadingBox();
}
};
var queryString = "?timestamp=" + new Date().getMilliseconds() + "&theService=" + theService;
if(isSyncCall == null)
isSyncCall = false;
ajaxRequest.open("POST", g_Service + queryString, isSyncCall);
ajaxRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ajaxRequest.send(params);
}
Update:
onLoad call to this service
function loadAdInfo(){
var theParamObj = {"REQUEST_URI" : window.location.href};
requestService('getAdInfo', theParamObj, false);
}
The XMLHTTPObject open method is defined like this:
open(method,url,async) Specifies the type of request, the URL, and if the request should be handled asynchronously or not.
method: the type of request: GET or POST
url: the location of the file on the server
async: true (asynchronous) or false (synchronous)
You are passing false. so you are calling it synch
I have to request data for a JS-script from a MySQL database (based upon a user-id).
I did not find a simple solution for JavaScript and it was not possible to load the data using ajax, because the database is available under a different domain.
I implemented a workaround using PHP and curl.
Now the JS has to "wait" for the request to finish, but the script is of course running asynchronously and does not wait for the response.
I know that it's not really possible to wait in JS, but it must be possible to return value like this.
I also tried using a return as another callback, but that didn't work of course, because the getter-function will run further anyway.
How can I implement a simple getter, which "waits" and returns the response from the HTTP-request?
Thanks for any other clues. I'm really lost at the moment.
This is a excerpt from the source code:
/**
* Simple getter which requests external data
*/
function simple_getter() {
// http request using a php script, because ajax won't work crossdomain
// this request takes some time. function finished before request is done.
/* Example */
var url = "http://example-url.com/get_data.php?uid=1234";
var response_callback = handle_result_response;
var value = send_request( url, response_callback );
value = value.split('*')[0];
if (value === '' || value == const_pref_none) {
return false;
}
/* 1. returns undefinied, because value is not yet set.
2. this as a callback makes no sense, because this function
will run asynchronous anyway. */
return value;
}
Additional information about the used functions:
/**
* Callback for the send_request function.
* basically returns only the responseText (string)
*/
function handle_result_response(req) {
// do something more, but basically:
return req.responseText;
}
/**
* Requests data from a database (different domain) via a PHP script
*/
function send_request( url, response_callback ) {
var req = createXMLHTTPObject();
if (!req)
return;
var method = (postData) ? "POST" : "GET";
req.open(method, url, true);
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
// More not relevant source code
// ...
req.onreadystatechange = function () {
// More not relevant source code
// ...
response_callback(req);
}
if (req.readyState == 4)
return;
req.send(postData);
}
Not really relevant code, but required for the HTTP-request:
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0; i<XMLHttpFactories.length; i++) {
try {
xmlhttp = XMLHttpFactories[i]();
} catch (e) {
continue;
}
break;
}
return xmlhttp;
}
You really, really shouldn't try to synchronously wait for a network request to complete. The request may never complete, may hang and take a long time, and so on. Since JavaScript is single threaded, and in fact all major browser engines are single threaded, this will cause your entire page to hang while waiting for the request, and in some browsers, may cause the entire browser to hang.
What you should do is replace code like this:
var returned = some_request('http://example.com/query');
do_something_with(returned);
with code like this:
some_request('http://example.com/query', function (returned) {
do_something_with(returned);
});
That way, you will never cause your page or the browser to hang waiting for the request, and can simply do the work once the response comes in.
I don't see whats wrong with your code in general.
When you make a request, provide a Callback. When a response comes back, which you can easily detect, execute the Callback and pass it the result.
This is the way client side apps work.It is not procedural, but works by events.
You present the screen to the user and wait
The user makes an action
You call the server, set a callback and wait
The response come and you execute the callback and wait for another step 2
Rather than trying to change that, you need to fit with that or it will be a painful experience.
Javascript is not multithreaded. It means a single statement is run at a time. The real asynchronism come from the time the server takes to respond and call the callback. You never know which call will come first and need to build your program with that in mind.
I have an issue, mainly with IE.
I need to be able to handle n queries one after another. But If I simply call my function below in a for loop IE does some strange things (like loading only so many of the calls).
If I use an alert box it proves that the function gets all of the calls, and surprisingly IT WORKS!
My guess is that IE needs more time than other browsers, and the alert box does just that.
Here is my code:
var Ajax = function(all) {
this.xhr = new XMLHTTPREQUEST(); // Function returns xhr object/ activeX
this.uri = function(queries) { // Takes an object and formats query string
var qs = "", i = 0, len = size(queries);
for (value in queries) {
qs += value + "=" + queries[value];
if (++i <= len) { qs += "&"; }
}
return qs;
};
xhr.onreadystatechange = function() { // called when content is ready
if (this.readyState === 4) {
if (this.status === 200) {
all.success(this.responseText, all.params);
}
this.abort();
}
};
this.post = function() { // POST
xhr.open("POST", all.where, true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(uri(all.queries));
};
this.get = function() { // GET
xhr.open("GET", all.where + "?" + uri(all.queries), true);
xhr.send();
};
if (this instanceof Ajax) {
return this.Ajax;
} else {
return new Ajax(all);
}
};
This function works perfectly for a single request, but how can I get it to work when called so many times within a loop?
I think the problem might be related to the 2 concurrent connections limit that most web browsers implement.
It looks like the latency of your web service to respond is making your AJAX requests overlap, which in turn is exceeding the 2 concurrent connections limit.
You may want to check out these articles regarding this limitation:
The Dreaded 2 Connection Limit
The Two HTTP Connection Limit Issue
Circumventing browser connection limits for fun and profit
This limit is also suggested in the HTTP spec: section 8.14 last paragraph, which is probably the main reason why most browsers impose it.
To work around this problem, you may want to consider the option of relaunching your AJAX request ONLY after a successful response from the previous AJAX call. This will prevent the overlap from happening. Consider the following example:
function autoUpdate () {
var ajaxConnection = new Ext.data.Connection();
ajaxConnection.request({
method: 'GET',
url: '/web-service/',
success: function (response) {
// Add your logic here for a successful AJAX response.
// ...
// ...
// Relaunch the autoUpdate() function in 100ms. (Could be less or more)
setTimeout(autoUpdate, 100);
}
}
}
This example uses ExtJS, but you could very easily use just XMLHttpRequest.
Given that the limit to a single domain is 2 concurrent connections in most browsers, it doesn't confer any speed advantage launching more than 2 concurrent requests. Launch 2 requests, and dequeue and launch another each time one completes.
I'd suggest throttling your requests so you only have a few (4?) outstanding at any given time. You're probably seeing the result of multiple requests being queued and timing out before your code can handle them all. Just a gess though. We have an ajax library that has built-in throttling and queues the requests so we only have 4 outstanding at any one time and don't see any problems. We routinely q lots per page.
Your code looks like it's put together using the constructor pattern. Are you invoking it with the new operator like var foo = new Ajax(...) in your calling code? Or are you just calling it directly like var foo = Ajax(...) ?
If the latter, you're likely overwriting state on your later calls. It looks like it's designed to be called to create an object, on which the get/post methods are called. This could be your problem if you're "calling it within a loop" as you say.