multiple ajax calls not working asynchronously (slow TTFB) - javascript

I've some simple ajax calls to populate drop down lists:
window.addEventListener('load', function () { GetDropDownData('http://mysite/controller/action/parameters1', '#ddl1') });
..
window.addEventListener('load', function () { GetDropDownData('http://mysite/controller/action/parameters4', '#ddl4') });
$.ajax({
url: url,
cache: true,
crossDomain : true,
dataType: 'jsonp',
type: "GET",
success: function (data) {
$(id).html(data);
},
error: function (reponse) {
$(id).html("error : " + reponse.responseText);
}
});
if I use them individually are fast, but used together are slow. This is evident in the images below.
The first time I use 1 call and it is fast, the second time I use 2 calls and the previous becomes slow now. The same with multiple calls.
Why this? And, can I solve it avoiding to merge the calls in a single call?

Session locking? One call comes in, locks the session, the second has to wait for the first to finish
Try switching session off and see if it improves
(I had the same problem once)
NB This answer only applies if the calls are asynchronous (as per the other comment)
http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/

Related

Carry out Javascript/jQuery functions in a sequence

I want to make some wine. And my function does:
function wine(){
growGrapes();
process(grapes);
makeWine();
bottle();
}
However, Since my functions often consist of $.ajax() request, some other functions get carried out first. I have used the success tool, but it helps for one ajax request only.
success:function(result){
//Some Code
}
What I actually want is a sequence.
Literally, grapes get processed before growing them. What is a easiest approach?
jQuery Deferred Objects & Promises are the way to go. http://api.jquery.com/category/deferred-object/
They supports running multiple tasks in parallel or series using $.when(PassArrayOfPromisesToRunInParallel) to run processes in parallel and promise.then() to run items sequentially.
Call the next function in the success handler of the $.ajax call of the previous function!
Example:
function growGrapes(){
// lines of code
$.ajax({
success: function(result){
// call next function here - process(grapes); and so on...
}
});
}
The above makes sure the functions get called sequentially after the other..
You can make your Ajax calls synchronous (in sequence) by ensuring you have async: false in your $.ajax() settings.
For example:
$.ajax({ url: 'url',
async: false,
dataType: 'json',
success: function(data) {
}
});
First solution :
Make your ajax call syncronous by setting async : false when setting up your ajax call
$.ajax
({
async : false,
/* other settings */
});
Warning: This solution causes the UI to hand on intensive processing. This should never be used when doing anything rigorous on the server. My recommendation for using this is to only use it in checking flags or loading simple data.
Second solution :
As stated in the comments, use jQuery promises to set up the ordering. Here is a tutorial
I'll try to come back and provide a code example for this solution soon
Third solution :
Make your next call the success handler, or call the next step from the success handler
$.ajax
({
success : NextStep,
/* other settings */
})
One solution is to use queue() function. This way you can execute as many functions as you want
var ajaxQueue = $({});
$.ajaxQueue = function(ajaxOpts) {
// queue the method. a second call wont execute until this dequeues
ajaxQueue.queue(function(next) {
// for this example I serialize params, but you can save them in several variables
// and concat into ajaxOpts.data
var params = method_that_get_params_and_serialize_them();
ajaxOpts.data = params;
ajaxOpts.complete = function() {
next();
};
$.ajax(ajaxOpts);
});
};
then your functions should be like this:
function growGrapes(){
$.ajaxQueue({
cache: false,
type: "POST",
url: "someUrl",
dataType: "json",
data: "", // we fill data inside ajaxQueue() method
success: function( response) {
//do things with response
}
});
}
If you want to keep it tidy and clean to let people see how your calls are made, you can simply pass a callback function to another like this:
function growGrapes(callback) {
$.ajax({
...
success: function (){
// Something
if (typeof callback === typeof Function) callback();
},
...
});
}
function wine(){
growGrapes(function (){
process(grapes);
});
}

Making an ajax request multiple times

I have three "sources," each of which needs to have an ajax call made. However, because Ajax is asynchronous, I can't just put it in a for loop. At the same time, I can't do async: false because it's bad to have the browser hang.
Thus, I decided to have the Ajax be called multiple times in it's success callback, and construct a kind of artificial loop. Problem is, it's not working properly (I'll explain the error later on in the question). Here's my relevant code.
counter: 0,
load: function(source, start_month, end_month, start_year, end_year) {
start_month = parseInt(start_month) + 1;
end_month = parseInt(end_month) + 1;
var parseDate = d3.time.format("%Y-%m-%d").parse;
if(source == 0) {
$.ajax({
dataType: "json",
url: ...
data: {
...
},
crossDomain: true,
success: function(raw_data) {
posts.counter++;
if(posts.counter < 4) {
alert(posts.counter);
posts.load(source, start_month, end_month, start_year, end_year);
} else {
alert("plot graph");
}
}
});
}
...
This entire code block exists inside a posts closure. Just a couple of questions:
Is this good style? Is there a more efficient way to go about doing this?
For some reason the alert is only firing twice... shouldn't it
be firing 3 times with 1, 2, and 3?
I suggest using JS promises (aka deferred objects). Look into jQuery's when and then functions (http://api.jquery.com/jquery.when/ and http://api.jquery.com/deferred.then/). You can use deferred objects to make 3 asynchronous calls and wait to process the data until all 3 calls return.

ajaxStop() doesn't fire

This is the code that wasn't working:
$(document).ajaxStop(function() {
$(this).unbind("ajaxStop"); //prevent running again when other calls finish
// Display everything
display();
});
And here's my Ajax function:
function getAjax(url, callback) {
jQuery.ajaxPrefilter(function( options ) {
options.global = true;
});
$.ajax({
url: url,
type: "GET",
dataType: "jsonp",
success: callback
});
}
Why does ajaxStop() never fire?
You'll notice I was making JSONP requests. It took me forever to find this, but the answer to this issue can be found here.
From the ticket:
JSONP requests are not guaranteed to complete (because errors are not
caught). jQuery 1.5 forces the global option to false in that case so
that the internal ajax request counter is guaranteed to get back to
zero at one point or another.
If you want all requests to fire the events, no matter what (and at the risk of the same inconsistencies 1.4.4 exhibited), you can use the following prefilter:
jQuery.ajaxPrefilter(function( options ) {
options.global = true;
});
Case in point: http://jsfiddle.net/X4JTx/

How to wait for an async call from a callback using jQuery?

I'm using the select2 jQuery based replacement for combo boxes, and I have to define a callback to process the data I receive from a json rest web service.
The problem is that, in the same callback, I have to issue another GET request to get the total numbers of matching records, so that select2 can decide if it has to load more results (it has an infinite scroll feature)
The code is something like this:
$("#country").select2({
ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
url: 'http://localhost:9000/api/countries',
dataType: 'json',
data: function(term, page) {
return {
filter: term,
page: page,
len: 10
};
},
results: function(data, page) {
return {
results: data, more: ????
};
}
}
});
The problem is I don't know how to issue an async request (I'm issuing a cross-domain request, and the docs says async is not supported in that case) and wait for it to finish before returning form the results callback.
The example from select2 page is like this:
results: function (data, page) {
var more = (page * 10) < data.total; // whether or not there are more results available
// notice we return the value of more so Select2 knows if more results can be loaded
return {results: data.movies, more: more};
}
The problem is that my web service returns the total number of records from a different endpoint, so I have to make another request, like this: http: //localhost:9000/api/countries?filter=term
any idea?
You can't wait for an async callback in javascript. You have to restructure your code to do all future work based on the async response from the actual callback.
If you need to make multiple consecutive ajax calls, then you issue the first one and in the success handler or response handler for the first ajax call, you issue the second ajax call and in the response handler for the second one, you carry out whatever you want to do with the data.
If see that you're using the .select2() framework. In the framework, the results callback is where the ajax call returns. It would be in that function that you would issue the second ajax call using normal jQuery ajax calls and in the success handler from that second ajax call, you would carry out whatever you're trying to do with the eventual data you got back. You won't be able to use the normal return value of the results callback because you won't have your final data yet at the point you need to return. I think this is just a limitation of .select2() in that it only supports a single ajax call. It just means you can't use a little bit of the built-in behavior and have to apply the result yourself with your own code, but it doesn't mean you have to throw out .select2() for everything else you were using it for.
It looks like you might want to just hook the change event directly and not use their built-in ajax stuff since it doesn't look like it really provides you with much if you need two serialized ajax calls.
I studied the source code on select2, and finnally came out with this solution
var ajax = {
url: 'http://localhost:9000/api/countries',
len: 3,
};
$("#country").select2({
query: function(options) {
var data = {
filter: options.term,
page: options.page,
len: ajax.len
};
$.ajax({
url: ajax.url,
data: data,
dataType: 'json',
type: 'GET',
success: function(data) {
$.ajax({
url: ajax.url + '/count',
data: { filter: options.term },
dataype: 'json',
success: function(resp) {
var total = parseInt(resp, 10);
var more = (options.page * ajax.len) < total;
options.callback({results: data, more: more});
}
});
}
});
},
});
As you can see, when te first fetch (ajax.url) completes I issue another request (ajax.url + '/count') and only when this second request completes I call options.callback, efectively serializing both ajax calls...
In fact the ajax function from select2 has more functionality, such as throttling and dropping out-of-order responses, I just ported them too, but I left them out of this response in order not to complicate the example...
In addition to jfriend00's answer (which is excellent, BTW) I found the followgin workaround, which is basically to issue the request synchronously, which in spite jquery docs it seemd to work (at least with chromium 18.0 and jquery 1.8.0)
I'm just posting it in case anybody find it useful...
var config = {
url: 'http://localhost:9000/api/countries',
len: 20,
term: ''
}
$("#country").select2({
ajax: {
url: config.url,
dataType: 'json',
data: function(term, page) {
config.term = term;
return {
filter: term,
page: page,
len: config.len
};
},
results: function(data, page) { // parse the results into the format expected by Select2.
var more = false;
$.ajax({
url: config.url + '/count',
data: { filter: config.term },
cache: false,
async: false,
success: function(resp) {
var total = parseInt(resp, 10);
more = (page * config.len) < total;
},
async:false
});
return {
results: data, more: more
};
}
}
});

javascript critical sections or semaphore problem

function myobj(){
var gup=this;
this.lastindex=-1;
this.criticalSectionInTimer=0;
this.updateTimer;
this.start = function(l){
if((typeof this.updateTimer)=="number"){
clearInterval ( this.updateTimer );
}
this.updateTimer=setInterval(function() {gup.getMessages();} , 30);
}
this.stop= function(){
if((typeof this.updateTimer)=="number"){
clearInterval ( this.updateTimer );
}
}
this.addUpdate(i){
//some code
}
this.rrrrnr=0;
this.getMessages = function (){
if(this.criticalSection==0){
this.criticalSection=1;
this.rrrrnr++;
console.log("in critical section"+this.rrrrnr);
var url="getmessages.php?lastindex="+this.lastindex;
$.getJSON(url,
function(data){
gup.lastindex=data.lastindex;
$.each(data.updates, function(i,item){
gup.addUpdate(item);
});
}
);
console.log("out critical section"+this.rrrrnr);
this.criticalSection=0;
}
}
}
var m= new myobj();
myobj.start();
I have the code from above. I have a main loop which makes updates at a given time interval. The problem is i have realized that it is getting in the "critical section" which I have delimited by the variable this.criticalSection .
From firebug i get the messages "in critical section" + index and "out critical section" +index in the right order but the ajax request is still being processed. But I get request with the same index and i really don't know where to look for the problem.
Are there any buildin features for semaphores or critical sections in javascript?
There aren't semaphores or critical sections because JavaScript is single-threaded. The ajax call you make is asynchronous, so it kicks off the request and then happily keeps going and leaving your critical section. As others have mentioned, a simple solution is to make the request synchronous, but this defeats the purpose of ajax.
Looking at your code, it seems like you are trying to get updates at regular intervals. If this is the case, why not schedule the next update in the callback of the ajax request?
this.getMessages = function (){
var url="getmessages.php?lastindex="+this.lastindex;
$.getJSON(url,
function(data){
gup.lastindex=data.lastindex;
$.each(data.updates, function(i,item){
gup.addUpdate(item);
});
gup.updateTimer=setTimeout(gup.getMessages, 30);
}
);
}
This would remove the need for semaphores, and is more in line with the event-driven nature of JavaScript. The downside is the updates are not done at exact intervals. Also, 30 milliseconds seems an extremely short interval.
jQuery send AJAX Async by default. Insted of doing getJSON try:
$.ajax({
dataType: 'json',
url: url,
type: 'GET',
async: false,
success: function(data){
gup.lastindex=data.lastindex;
$.each(data.updates, function(i,item){
gup.addUpdate(item);
});
});
The proble is fairly simple.
You are using AJAX, which, by definition, is asynchronous. That means, you execute $.getJSON, and the js will continue and exit the critical section while the request is being processed. Therefore, several calls to getMessages can be performed before the first requests completes.
It seems that you intend such a getJSON call NOT not be async, and be blocked within the critical section until it ends. To do so, you must set the async property to false, something in the lines of:
$.ajax({
dataType: 'json',
url: "getmessages.php?lastindex="+this.lastindex,
type: 'GET',
async: false,
success: function(data){
gup.lastindex=data.lastindex;
$.each(data.updates, function(i,item){
gup.addUpdate(item);
});
});

Categories

Resources