Unable to retrieve data from parallel ajax calls - javascript

I have a function below (searchTerm) which is supposed to fetch data from two URL's simultaneously and display the result after both the calls are completed.
This is working fine when I call with only one parameter in .when (say $.ajax(options1)),
but as I need the output from both in parallel, I am calling both URL's and recording responses data1 and data2 in .then function, but now it is not getting called after the ajax calls are completed.
Can anyone tell if I am correct in this approach? If so, then why is the callback not getting executed?
var searchTerm = function() {
var $a = $(this);
var term = $("#searchbox").val();
var options1 = {
url: "someurl1",
contentType: "application/json",
data: JSON.stringify({
searchString: term
}),
type: "post",
dataType: "html"
};
var options2 = {
url: "someurl2",
contentType: "application/json",
data: JSON.stringify({
searchString: term
}),
type: "post",
dataType: "html"
};
$.when($.ajax(options1), $.ajax(options2)).then(function(data1, data2) {
alert("callbacks finished");
});
Info1:
It seems any ajax call I specify as first argument is failing with 500 server error. I tried swapping options1 and options2, and now the call with options2 fails.
Info2:
The url that I have mentioned as part of options1 and options2 point to action methods in the same controller and they both return awaitable Task of (ActionResult) object. Can this be the problem here? Are the calls somehow blocking/interrupting each other over async requests?
Info 3:
Trying to provide more details to work with. The definition of the action methods are like this -
public async Task<ActionResult> someurl1(.....){
...
...
return await View(...);
}

Finally, I found the answer after debugging through all the subsequent calls. I was calling a common function from both action methods which uses a global variable to make external URL calls. Simply used the below locking mechanism to make my critical section thread-safe.
public static object Lock = new object();
lock (Lock) // added for thread safety purpose
{
response_task = CallExtern(...)
}

Try adding the option
async: false
to the ajax objects.

Related

AJAX call using IIFE? Can't seem to get .done to work the same as a regular function

I currently have an AJAX call out to a PHP file that works, that is the following:
//Load map from database
function getMap(){
return $.ajax({
url: "getMap.php",
type: "POST",
dataType: 'JSON',
});
};
getMap().done(function(r) {
if (r) {
loadedMap(JSON.parse(r.mapArray), JSON.parse(r.mapProperties)); //call loadedMap(r) if loading a map from DB
} else {
console.log("No data");
}
}).fail(function(x) {
console.log("error");
});
That works within a single javascript file that successfully passes r.mapArray and r.mapProperties to my main loadedMap function.
I'm trying to learn about the IIFE Javascript Module model, and split my work up into separate files.
So, I currently have main.js:
(function() {
// let's get our map
var gameMap = mapGen.getMap().done();
console.log(gameMap);
})();
and mapGen.js:
var mapGen = function() {
return {
getMap: function() {
return $.ajax({
url: "getMap.php",
type: "POST",
dataType: 'JSON',
});
}
};
}()
If I console.log(gameMap), I see the responseText JSON object with my data. I just can't seem to access it. console.log(gameMap.responseText) is undefined. as is gameMap.responseJSON (though I see both of them in the console).
Looking the code over it looks as the the separation of the files was not the issue and that looks to be implemented correctly. The issue is with how you are handling the AJAX request. The function mapGen.getMap() actually returns a jqXHR Object as opposed to the response that you are trying to access.
Just as you had in your previous file, you will need handle the response of your request.
(function() {
// let's get our map request
var gameMap = mapGen.getMap();
gameMap.done(function(r){ ... }).
fail(function(x){ ... });
})();
You will be able to access the response data you are looking for within the done() function.

extract object of responseJSON

I solved a synchronous problem with ajax that way to use deferred function.
I get as an response now big object with statusResponse etc etc inside.
My JSONP Objects are also successfully stored in responseJSON Object. How Can I extract it or save it in another variable ?
var web = new webService();
web.init(app.info);
and here the class
function webService() {
this.init = function(app) {
var d = this.connect(app).done(function(){});
console.log(d);
}
this.connect = function(app) {
console.log(app);
return $.ajax({
url: 'working url',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000
});
}
}
.done() is going to be called when the data has returned (but through a parameter). So, make sure you add a parameter to your callback function then inspect it for whatever you want out of it.
this.connect(app).done(function(mydata){
// mydata = the response object
// grab whatever information you want from it here.
});

Why is AJAX/JSON response undefined when used in Bootstrap typeahead function?

I created a function that makes a jquery AJAX call that returns a JSON string. On its own, it works fine -- and I can see the JSON string output when I output the string to the console (console.log).
function getJSONCustomers()
{
var response = $.ajax({
type: "GET",
url: "getCustomers.php",
dataType: "json",
async: false,
cache: false
}).responseText;
return response;
};
However, when I set a variable to contain the output of that function call:
var mydata = getJSONCustomers();
, then try to use it within my Twitter-Bootstrap TypeAhead function (autocomplete for forms):
data = mydata;
console.log(data);
I get an 'undefined' error in my console.
Below is a snippet of this code:
$(document).ready(function() {
var mydata = getJSONCustomers();
$('#Customer').typeahead({
source: function (query, process) {
customers = [];
map = {};
data = mydata;
console.log(data);
// multiple .typeahead functions follow......
});
Interesting here, is that if I set the data variable to be the hardcoded JSON string returned from the AJAX function, everything works fine:
data = [{"CustNameShort": "CUS1", "CustNameLong": "Customer One"}]
How can I use the JSON string within my typeahead function?
.responseText returns a string. You have to parse the string first to be able to work with the array:
var mydata = JSON.parse(getJSONCustomers());
That being said, you should avoid making synchronous calls. Have a look at How do I return the response from an asynchronous call? to get an idea about how to work with callbacks/promises.
The problem is that the Ajax request hasn't had the chance to complete before typeahead is initialised, so typeahead is initialised with an uninitialised mydata variable. Also, as of jQuery 1.8+ async: false has been deprecated and you need to use the complete/success/error callbacks.
Try this:
function getJSONCustomers(callback) {
$.ajax({
type: "GET",
url: "getCustomers.php",
dataType: "json",
cache: false,
success: callback
});
};
And then you could do something like:
getJSONCustomers(function(mydata) {
// mydata contains data retrieved by the getJSONCustomers code
$('#Customer').typeahead({
source: function (query, process) {
customers = [];
map = {};
console.log(mydata);
// multiple .typeahead functions follow......
});
});
So your code completes the Ajax call before initialising the typeahead plugin.

get a callback function to add to object javascript

I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}

jQuery ajax function return

I have this function that embeds flash :
function embedswfile(target, swf, base, width, height) {//dosomething}
And I want to call the function like this
embedSwf("flashgame",decode("<?=base64_encode($path['location'])?>"),decode("<?=base64_encode($path['base_directory'])?>"),"800","600" )
The idea is that whenever someone looks for any swf inside my website,he wont find anything clean.I will change the encoding algorithm,but this is just temporary. In order for that function to work,whenever I call the function 'decode' it must return a single value. PHP contains
<?php
echo base64_decode($_POST['s']);
?>
I tried this but it still wont work
var globvar;
function processdata(newmsg) {
globvar = newmsg;
}
function decode(s){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(newmsg){
processdata(newmsg);
}
});
return globvar;
}
Important:
Forget about using Ajax and encoding, decoding the path. What do you think you gain from it? Security? No. One can figure out that this is bas64 encoded or he just monitors the network traffic and reads the response from the Ajax call.
Just do
embedSwf("flashgame","<? =$path['location']?>"),"<?=$path['base_directory']?>","800","600" )
Really, you cannot prevent someone else seeing the data and are just making things more complicated for you.
(Or you have to decrypt the data with JavaScript.)
(original answer is still correct nevertheless)
Ajax is asynchronous so something like var test = decode(s); will never work. The decode function will return before the Ajax call finishes.
Instead, put your logic into the callback handler. For example, if your code was this before:
var retdata = decode('s');
// here comes code that handles retdata
put the code into a function and call it from the success handler:
function process(retdata) {
// here comes code that handles retdata
}
function decode(s){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(newmsg){
process(newmsg);
}
});
}
This seems to be a very common problem to all beginners. You will find a lot of questions here that deal with the same problem.
Update:
It is not nice, but you could change the function to
function decode(s, cb){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(data){
cb(data);
}
});
}
and do
decode("<?=base64_encode($path['location'])?>", function(location) {
decode("<?=base64_encode($path['base_directory'])?>", function(dir) {
embedSwf("flashgame",location,dir,"800","600" );
});
});
Update 2:
For completeness, you can make the Ajax call synchronous, by using async: false. Then this will work:
function decode(s){
var ret;
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
async: false,
success:function(newmsg){
ret = newmsg;
}
});
return sync;
}
var val = decode(s);
However, this will block the browser until the Ajax call finished. You have to test whether this matters in your case or not.
Update 3:
You could also change your PHP script to not only accept one parameter but several and process both strings in one go.

Categories