Getting value from Ajax request in variable - javascript

I've this function.
function ajaxtakesource4(callback){
var ajaxRequest; // The variable that makes Ajax possible!
try{
ajaxRequest = new XMLHttpRequest();
} catch (e){
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange =function(){
if(ajaxRequest.readyState == 4 &&ajaxRequest.status==200){
var sourcetest = ajaxRequest.responseText;
callback(sourcetest);
}
}
ajaxRequest.open("POST", "takesource4.php", true);
ajaxRequest.send(null);
}
Also:
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
});
alert(somous4);
}
and here I call the above the function:
<div id="run">
<button id="button_run" class="button" onclick="run()">Run</button>
</div>
When I click on the button it's supposed to alert response from Ajax request, but looks to be alerting a falsy value (undefined), as seen in this line:
alert(somous4);

I suggest you change the callback in the run function as follows:
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
alert(somous4);
});
}

You're alerting somous4 before it's changed by the request callback. In this case the commands block executes first than the request callback.
Server-side languages as PHP does the work automatically, so you don't need to use events there. It sleeps while the request is not done. That's because the commands block turns the event callback.

Asynchronous code executes concurrently in nature. Thus, your alert statement may execute before your callback executes (callback will only after it receives back data from server). Put the alert inside the callback and it will show the value returned i.e.
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
alert(somous4);
});
}
Edit: Based on OP's comment, instead of thinking about return values, do this:
function foo(soumous4) { // use somous4 for whatever you want... }
// Call this function foo inside the callback.
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
foo(somous4);
});

Related

How to make asynchronous function work like a regular one?

I have a code that XMLHttpRequest. It's a object to send request to server and it's asynchronous so when I want to receive the response I need to provide the callback function to onreadystatechange property of this object. And this function is called after response being received:
function send()
{
XMLHttpRequest req = new...
req.onreadystatechange = answer;
}
function answer()
{
//handling the answer...
}
So it's great but I don't want to use new function to handle answer so I do it anonymous:
function send()
{
XMLHttpRequest req = new...
req.onreadystatechange = function ()
{
//handling the answer...
};
}
But now i want to use the result of send function in another function for example to display result:
display(send())
So how to make this work? Something like:
function send()
{
XMLHttpRequest req = new...
req.onreadystatechange = function ()
{
//handling the answer...
return result; //where result is returned by send function
};
}
Is there any way to do this so that other JS code will still work while this code will handle the response?
With asynchronous functions you need to do it the opposite way. Instead of saying display(send()) you need to sue send(display)
function send(callback)
{
XMLHttpRequest req = new...
req.onreadystatechange = function ()
{
//handling the answer...
callback(result);
};
}
Trying to write display(send()) won't work. The send() function produces a value asynchronously but returns promptly. It can't return the result of the async operation.
Inside the readystatechange handler, the response is available on req.responseText. You should put your call to display() inside that event handler.
You can use synchronous AJAX call:
XMLHttpRequest req = new...
var result = null;
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
result = req.responseText;
}
}
};
req.open('GET', url, false); //async = false
return result;
But this is a poor practice and not an idiomatic way of working with JavaScript. Quoting Synchronous and asynchronous requests:
Note: You shouldn't use synchronous XMLHttpRequests because, due to the inherently asynchronous nature of networking, there are various ways memory and events can leak when using synchronous requests.
You know how to use callbacks, why not simply:
send(display)

javascript array empty outside a function

I have JavaScript code like this:
var buffer=new Array();
function fetchData(min,max){
var ajaxReq = new XMLHttpRequest();
ajaxReq.onreadystatechange = function(){
if (ajaxReq.readyState === 4) {
if (ajaxReq.status === 200) {
buffer= ajaxReq.responseText;
console.log(buffer)//this logs an array to console
} else {
console.log("Error", ajaxReq.statusText);
}
}
};
ajaxReq.open('GET', "server/controller.php?min="+min+"&max="+max, true);
ajaxReq.send();
}
fetchData(1,100);
console.log(buffer);//this log an empty array
two logs with different result, what am I doing wrong? thanks for pointers.
Ajax is asynchronous. That means that console.log(buffer) at the end is executed before the response from the Ajax request.
You should change your method to this:
function fetchData(min,max,callback){
var ajaxReq = new XMLHttpRequest();
ajaxReq.onreadystatechange = function(){
if (ajaxReq.readyState === 4) {
if (ajaxReq.status === 200) {
buffer= ajaxReq.responseText;
callback();
//console.log(buffer)//this logs an array to console
} else {
console.log("Error", ajaxReq.statusText);
}
}
};
ajaxReq.open('GET', "server/controller.php?min="+min+"&max="+max, true);
ajaxReq.send();
}
fetchData(1,100,function(){
console.log("My Ajax request has successfully returned.");
console.log(buffer);
});
You are trying to log() the buffer before the AJAX request in executed. To solve this, your fetchData function needs to handle a callback function.
var buffer=new Array();
function fetchData(min,max, callback){
var ajaxReq = new XMLHttpRequest();
ajaxReq.onreadystatechange = function(){
if (ajaxReq.readyState === 4) {
if (ajaxReq.status === 200) {
buffer= ajaxReq.responseText;
console.log(buffer)//this logs an array to console
if(typeof callback == 'function'){
callback.call(this);
}
} else {
console.log("Error", ajaxReq.statusText);
}
}
};
ajaxReq.open('GET', "server/controller.php?min="+min+"&max="+max, true);
ajaxReq.send();
}
fetchData(1,100, function(){
console.log(buffer);
});
This is the most basic implementation, and will work only if the AJAX response is successful.
This is asynchronous. So your flow goes like this:
call fetchData()
ajax request is sent, registering an onreadystatechange callback
fetchData() completes and returns
buffer is logged out, which doesn't yet contain anything.
Sometime later, the ajax request completes and triggers the callback
The callback puts things in the array.
buffer get's logged out from the callback, and you see it now has items in it.
So you are only starting the asynchronous request once you hit that first console.log. But it actually finishes long afterward.
A couple of issues here. When the ajax call completes the 2nd console.log has already executed before the variable was set.
Also,You're not using the buffer varaible as an Array.
Seems right to me. buffer is empty to start and it doesn't get set until AFTER the asynchronous call is made, so even though you're fetchingData before the second console.log, you're not receiving it until after it shows an empty buffer.
MDN: https://developer.mozilla.org/en/XMLHttpRequest
void open(in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password);
The third argument is used to tell the browser whether the request should be made asynchronous or not. You set it to true, thus it will be async.
Async basically means that the request is sent and meanwhile other code is executed. So, it starts the request, and while waiting for a response, it logs the buffer: before the request has finished. If you want to log the contents, do it in the onreadystatechange event or set the third argument (async) to false.

How can I make XHR.onreadystatechange return its result?

I'm new to JavaScript programming. I'm now working on my Google Chrome Extension. This is the code that doesn't work... :P
I want getURLInfo function to return its JSON object, and want to put it into resp. Could someone please fix my code to get it work?
function getURLInfo(url)
{
var xhr = new XMLHttpRequest();
xhr.open
(
"GET",
"http://RESTfulAPI/info.json?url="
+ escape(url),
true
);
xhr.send();
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
return JSON.parse(xhr.responseText);
}
}
}
var resp = getURLInfo("http://example.com/") // resp always returns undefined...
Thanks in advance.
You are dealing with an asynchronous function call here. Results are handled when they arrive, not when the function finishes running.
That's what callback functions are for. They are invoked when a result is available.
function get(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
// defensive check
if (typeof callback === "function") {
// apply() sets the meaning of "this" in the callback
callback.apply(xhr);
}
}
};
xhr.send();
}
// ----------------------------------------------------------------------------
var param = "http://example.com/"; /* do NOT use escape() */
var finalUrl = "http://RESTfulAPI/info.json?url=" + encodeURIComponent(param);
// get() completes immediately...
get(finalUrl,
// ...however, this callback is invoked AFTER the response arrives
function () {
// "this" is the XHR object here!
var resp = JSON.parse(this.responseText);
// now do something with resp
alert(resp);
}
);
Notes:
escape() has been deprecated since forever. Don not use it, it does not work correctly. Use encodeURIComponent().
You could make the send() call synchronous, by setting the async parameter of open() to false. This would result in your UI freezing while the request runs, and you don't want that.
There are many libraries that have been designed to make Ajax requests easy and versatile. I suggest using one of them.
You can't do it at all for asynchronous XHR calls. You cannot make JavaScript "wait" for the HTTP response from the server; all you can do is hand the runtime system a function to call (your handler), and it will call it. However, that call will come a long time after the code that set up the XHR has finished.
All is not lost, however, as that handler function can do anything. Whatever it is that you wanted to do with a return value you can do inside the handler (or from other functions called from inside the handler).
Thus in your example, you'd change things like this:
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
var resp = JSON.parse(xhr.responseText);
//
// ... whatever you need to do with "resp" ...
//
}
}
}
For small edit talking about post: https://stackoverflow.com/a/5362513/4766489
...
if (typeof callback == "function") {
//var resp = xhr.responseText;
var resp = JSON.parse(xhr.responseText);
callback(resp);
}
...
And when you call
...
function(data) {
alert(data);
/* now do something with resp */
}
...

Ajax responseText comes back as undefined

I'm having problems with this piece of code; the return value comes back as 'undefined'. What's the problem?
var fx = null;
xmlhttp.open("GET", URL ,false);
xmlhttp.onreadystatechange=function()
{
alert("enter func");
if (xmlhttp.readyState==4)
{
if (xmlhttp.status == 200)
{
alert(fx);
fx = xmlhttp.responseText;
return fx;
}
else
{
alert("Error" + xmlhttp.statusText);
}
}
}
Newer code:
function getData(callback)
{
xmlhttp.open("GET", URL ,false);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status == 200)
{
alert(xmlhttp.responseText);
cbfunc(xmlhttp.responseText);
}
else
{
alert("Error" + xmlhttp.statusText);
}
}
}
xmlhttp.send(null);
}
How I'm calling it:
getData( function cbfoo(txt)
{
//document.form.autodate.value=txt;
alert(txt);
alert(document.form.autodate.value);
});`
Update based on your edit
function getData(callback)
{
// you should move the creation of xmlhttp in here
// so you can make multiple getData calls if needed
// if you keep xmlhttp outside the function the different calls to getData will interfere
// with each other
xmlhttp.open("GET", URL ,false); // false should be true, to make it async
...
{
alert(xmlhttp.responseText);
cbfunc(xmlhttp.responseText); // your function gets passed as the
// parameter "callback" but you're
// using "cbfunc" here instead of "callback"
...
getData(function cbfoo(txt) // you can omit the function name here
...
Fixing those issues should make the code work.
Old answer
You're calling the XMLHttpRequest in Synchronous mode, that means that it will block the script until the request has finished, since you're assigning the onreadystatechange callback after the blocking call (that means after the request has already finished) your code never gets notified.
Since the synchronous mode blocks the script, it also blocks the Browser's UI, so it's not recommended to use this mode.
You should (for 99% of the cases) use the Asynchronous mode and use a callback to handle the data, since xmlhttp.open does not return the return value of the onreadystatechange callback, it simply returns undefined immediately when run in async mode.
Now a common pattern is to write a wrapper for the request and pass an anonymous function to this wrapper, which later will get called back when the request has finished.
function doRequest(url, callback) {
var xmlhttp = ....; // create a new request here
xmlhttp.open("GET", url, true); // for async
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
if (xmlhttp.status == 200) {
// pass the response to the callback function
callback(null, xmlhttp.responseText);
} else {
// pass the error to the callback function
callback(xmlhttp.statusText);
}
}
}
xmlhttp.send(null);
}
You can now do a request and supply a function that will get called as soon as the request finishes, inside of that function you then do whatever you want to do with the response.
doRequest('http://mysite.com/foo', function(err, response) { // pass an anonymous function
if (err) {
alert('Error: ' + err);
} else {
alert('Response: ' + response);
}
});
This is the common programming model in the browser, always go with a asynchronous solution, if you block the script you block the whole Browser.

Implement delay in javascript without killing the processor

I want to return the function when a certain time has passed. In my function below the return thing didn't work(the alert was triggered).
The thing is that in my handleRequestStateChange I initialize myArray.
function() {
xmlHttp.open("POST", "xxx", true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length", 10);
xmlHttp.onreadystatechange = handleRequestStateChange;
xmlHttp.send(locParam);
setTimeout(function() { return myArray; }, 5000);
alert("end sleep");
}
Thanks!
As you're aware, timers are delayed until later in the thread, but the function that calls them continues to execute straight away. There's no way to delay the currently executing function without locking up the browser and preventing user interaction with the browser.
This is where the point of callbacks come into play. Instead of trying to delay continued execution of code, you supply a function as a parameter to the "delaying" function, and when it has it's necessary data ready, it executes the callback function with the data as a parameter.
function submitRequest(callback) {
xmlHttp.open("POST", "xxx", true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length", 10);
xmlHttp.onreadystatechange = function ()
{
if (xmlHttp.readyState == 4 && xml.status == 200)
{
var myArray;
// do something with data
callback(myArray); // execute the callback function
}
};
xmlHttp.send(locParam);
}
function someCallingFunction()
{
// call submitRequest with an anonymous function as the callback parameter
submitRequest(function (myArray)
{
alert("end sleep");
// do something with myArray
});
}
You can put the sleep for certain time, then put the return statement after
the sleep.
So that it will return from the function after some time is passed.

Categories