I've got a variable responce which is assigned via an AJAX function send(). When I make the assignment...
responce = send();
response returns before send does giving me back an undefined how can I add a callback to prevent this from happening?
EDIT: a clarification on what I'm asking..
It's still returning undefined. I'm assigning the variable with the function send send returns onreadystatechange however when my code is executing.. response returns as undefined before send() can return. How do I stop the code under response from running on till response has been assigned sends value?
EDIT2:
The following code is my send function...
function send(uri)
{
var xhr = new XMLHttpRequest();
xhr.open("POST",uri,true);
xhr.onreadystatechange = function (send){
if(xhr.readyState == 4){
return xhr.responseText;
}
}
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
xhr.send(null);
}
You are using Ajax in a asynchronous manner, but you are treating it to be synchronous.
Asynchronous calls goes off to do its job while the rest of the code after the initial send call executes. You are getting undefined because the code is not returning anything.
If you look at the XMLHttpRequest object, the 3rd argument in the open method is the asynchronous flag.
open("method", "URL"[, asyncFlag[, "userName"[, "password"]]])
Setting it to true [default is left off] will make an asynchronous call. Setting it to false will make it synchronous.
The problem with using synchronous calls is it locks up the user's browser until the call is returned. That means animated gifs stuff, browser timers stop, and so on. If the server takes forever to respond, the user can not do anything.
The best solution is to avoid using synchronous calls. Use the call back to continue the code execution flow.
So based on your edit, I will edit my response with a basic solution
function send(uri, callback)
{
var xhr = new XMLHttpRequest();
xhr.open("POST",uri,true);
xhr.onreadystatechange = function (send){
if(xhr.readyState == 4){ //You really should check for status here because you can get 400, 500, etc
callback(xhr.responseText);
//return
}
}
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
xhr.send(null);
}
function myFunction(){
var myUrl = "foo.php";
//show a loading message or soemthing
var someDiv = document.getElementById("loadingMessage");
someDiv.style.display = "block";
//Second half of your function that handles what you returned.
function gotData( value ){
someDiv.style.display = "none";
alert(value);
}
send(myUrl, gotData);
}
If you really want to do synchronous and you do not mind locking up a user's browser
function send(uri, callback)
{
var xhr = new XMLHttpRequest();
xhr.open("POST",uri,false);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
xhr.send(null);
if(xhr.status==200){
return xhr.responseText;
}
else{
return null;
}
}
I presume you are talking about the XMLHTTPRequest.send() method, rather than a framework's wrapper.
send does not return anything. It will always return undefined.
To get the HTTP response, you need to monitor onreadystatechange, as countless StackOverflow answers and internet tutorials (e.g. this one) demonstrate.
you must assign the value to your response on readystatechange event of your request, something like this:
req.onreadystatechange = function(){
if (req.readyState===4) { // checks if data is already loaded.
callback(req.responseText,req.status); //call your callback function with response and status as parameters.
}
};
try this:
function send(uri, callback)
{
var xhr = new XMLHttpRequest();
xhr.open("POST",uri,true);
xhr.onreadystatechange = function (send){
if(xhr.readyState == 4 and callback){
callback();
}
}
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
xhr.send(null);
}
send("uri here", function(){
//whatever needs to be done after request
})
Related
I have a AJAX call to retrieve some XML using the below method. Often when I run the code it does not enter the onreadystatechange function until the last iterations of my foreach loop. I'm assuming this is because the calls to "www.webpage.com/" + arrayValue are taking enough time that before the state is updated to "Ready" and then the next request beings. The method probably only runs for the last iteration of the loop because there is no other request to override it and thus has time to become "Ready". From what I've seen online you can't really do a tradition Wait() statement in javascipt or AJAX to give the calls time to complete. So how can I overcome this issue?
var getXML = new XMLHttpRequest();
myArray.forEach((arrayValue, index) => {
getXML.open("GET", "www.webpage.com/" + arrayValue, true);
getXML.setRequestHeader('Access-Control-Allow-Credentials', true);
getXML.setRequestHeader('Authorization', "Basic " + btoa(":something"));
getXML.send(null);
getXML.onreadystatechange = function () {
if(this.readyState == this.DONE) {
Console.Log("We made it in!");
}
}
});
The problem here is that you are trying to use the same XMLHttpRequest object for multiple requests.
Don't do that. Create a new, clean instance of XMLHttpRequest for each request.
myArray.forEach((arrayValue, index) => {
var getXML = new XMLHttpRequest();
getXML.open("GET", "www.webpage.com/" + arrayValue, true);
Trying to get my head around http requests and asynchronous javascript behaviour.
function httpGetAsync(url, callback){
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
console.log(xmlHttp.responseText); // prints the ip address
callback(xmlHttp.responseText);
}
}
xmlHttp.open("GET", url, true)
xmlHttp.send(null);
}
httpGetAsync("http://httpbin.org/ip", function(){
console.log(this); // doesn't print the ip address
})
The http request is just a simple one that returns a json formatted ip address of the get request. In the function definition the ip address can be printed to the console just fine however in the callback the console prints out the window object. this is probably the wrong thing to use, how do I access the data in xmlHttp.responseText in the callback?
callback(xmlHttp.responseText);
You are calling a function. You are passing it an argument.
function(){
console.log(this); // doesn't print the ip address
}
Your function is not expecting to receive any arguments. Change that, then use that argument.
function(my_argument){
console.log(my_argument);
}
See also How does the “this” keyword work?
You're calling callback(xmlHttp.responseText), so...
httpGetAsync("...", function(response) {
console.log(response);
});
Simple!
One small point: I would recommend putting the .open call before the onreadystatechange, because in some (older) browsers calling .open will reset event handlers.
I have Javascript code that uploads files to a server. Each upload is done using a XMLHttpRequest object.
xhr = new XMLHttpRequest();
//...
xhr.open('POST', 'https://<bucket>.s3.amazonaws.com/', true);
xhr.send(fd);
The upload in parallel works fine. The problem is that I need to detect when all of them have finished, because I have to do a final submit, but only if all the uploads are completed.
My first try was save all the xhr objects in an array but I didn't know what to do with that :-(
var arrayxhr = [];
//...
//A loop {
xhr = new XMLHttpRequest();
arrayxhr.push(xhr);
xhr.open('POST', 'https://<bucket>.s3.amazonaws.com/', true);
xhr.send(fd);
//}
//And now?
I found this jQuery function https://api.jquery.com/ajaxcomplete/, but the same, I don't really know how to use it.
Can you help me please?
TIA,
If you can use jQuery you can use jQuery AJAX Deferred interface/methods and $.when method. $.ajax/$.post/$.get and other jQuery AJAX methods always return jQuery Deferred object:
$.when($.get('someUrl'), $.get('anotherUrl')).then(function () {
//all request complete
});
In native javascript you can use native Promise or any promise library:
http://www.javascriptoo.com/rsvp-js
http://www.javascriptoo.com/Q (example https://gist.github.com/matthewp/3099268)
Also good article about Promises - http://www.html5rocks.com/en/tutorials/es6/promises/.
Native Promise with XMLHttpRequest example:
function doAjaxRequest(method, url, data){
var promise = new Promise();
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
// Register the event handler
xhr.onload = function(){
if(xhr.status === 200){
promise.resolve("Done");
} else{
promise.reject("Failed");
}
};
data = data || {};
xhr.send(data);
return promise;
}
Promise.all(doAjaxRequest('post', 'someUrl'), doAjaxRequest('post', 'anotherUrl')).then(function (values) {
//all request complete
});
Well, this is not exactly the answer to my question (detect that the asynchronous calls are completed), but this answer works for me. I copy here just in case it helps someone else:
2: On the client-side, create a stack of files to upload and upload
one at a time, calling the next one on the "Complete" callback of the
previous.
https://stackoverflow.com/a/15557631/1893936
I'm doing an AJAX call (regular JS) and, if it takes more than, say, 500 milliseconds, I'd like to put up my "Please Wait" box.
Normally, if I want to put up the PW box immediately, I'd do:
// show semi-transparent grey screen to block access to everything underneath
divGreyCoverAllNode.style.display = 'inline';
// show PW box. Prior to these lines, both coverall and PW were display=none
divPleaseWaitNode.style.display = 'inline';
// now do the AJAX and follow-up inside a zero timer; the timer is necessary to
// make the system pause to display the screen changes we previously invoked
setTimeout( function() {
// do my ajax call here, then after the call...
// take down the PW stuff
divPleaseWaitNode.style.display = 'none';
divGreyCoverAllNode.style.display = 'none';
},
0
);
Like I stated above, what I'd like to do is have the PW displayed only if AJAX doesn't finish in, say, 500 milliseconds. Ideally it would be something like:
// set a timer to display PW in 500 milliseconds
myTimeEvent = setTimeout( function() {
divGreyCoverAllNode.style.display = 'inline';
divPleaseWaitNode.style.display = 'inline';
},
500
);
// do my ajax call here, then after the call...
clearTimeout(myTimeEvent);
// take down the PW stuff, in case it was displayed
divPleaseWaitNode.style.display = 'none';
divGreyCoverAllNode.style.display = 'none';
But I can't seem to get the system to pause and display the PW when AJAX is taking its time. I've tried surrounding the AJAX-and-follow-up block in a zero timer, but no deal.
Any suggestions?
EDIT:
Important fact: This is not an asynch ajax call. It's an unusual situation that requires everything to wait on the ajax result.
Given that you are making a synchronous XHR call, you can't. That's the nature of synchronous – everything stops until the call completes. When you use a synchronous XHR request, not only is the JavaScript event loop stopped, you actually freeze the entire browser UI (in IE and Firefox < 3).
That said, you're doing it wrong. 8.4% of reported IE9 hangs last month were due to synchronous XHR. There really is no such thing as ‘an unusual situation that requires use of synchronous XHR requests.’ Make your request, then act on the data you get in the callback function.
Instead of something like:
// Do stuff, then when you need a request:
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send();
// Do more stuff
alert(xhr.responseText);
You need:
// AJAX helper
function req(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) callback(xhr);
}
}
// Your code. Do stuff, then when you need an AJAX request:
req(url, function(xhr) {
// Do more stuff
alert(xhr.responseText);
});
Obviously this needs refined, but this illustrates the proper way to make an AJAX request.
It shouldn't come after the ajax call, it should come inside the callback function. AJAX requests are asynchronous with the rest of the code, you should preform actions you want upon completion inside the callback part of your request.
take a look at BlockUi. If that doesn't look like it will work for you, you could try using
$(document).ajaxStop(DoSomething());
Take a Look at jQuery Timeout
document.getElementById('contactButton').value = "Sending";
xmlhttp.onreadystatechange=stateChanged;
xmlhttp.open("GET",url,false);
xmlhttp.send(null);
function stateChanged(){
if (xmlhttp.readyState==4) {
var response = xmlhttp.responseText;
if(response == "true"){
document.getElementById('contactButton').value = "Sent :)";
}
}
When running this javascript, contactButton never gets set to "Sending...". It hangs for one second, and then changes to "Sent :)".
I'm not real sure about the processing order of javascript, but it seems like it needs some sort of task switch to process the XMLHttpRequest().
This is obviously an abbreviated code, but I have several other javascript/css things I am trying to do before the xmlhttp. It seems like the xmlhttp just takes over when the request is sent.
Any ideas?
You're passing false to open, so it's running synchronously. That means it doesn't use the readyState and instead just delays until the request completes. If you want to do sync, it should be:
xmlhttp.open("GET",url,false);
xmlhttp.send(null);
if(xmlhttp.status == 200)
{
var response = xmlhttp.responseText;
document.getElementById('contactButton').value = "Sent :)";
}
You should change to async to avoid hanging your script, and you will probably find it easier to use a JavaScript library.