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/
Related
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/
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);
});
}
I'm using jquery ui and sortable, I want to combine this with an Ajax call on the change event:
$("#events").sortable({
change: function (event, ui) {
$.ajax({
type: "POST",
url: "/tasks/updateTaskUserPosition",
dataType: "json",
data: {
taskId: ui.item.data("task-id")
},
success: function (result) {
if (result == "error") {
alert("Not possible!");
return false;
}
}
});
}
});
I want the change event to return false (IE, reset the position change) if a condition is met on Ajax success, essentially I need to "crawl" back a function. How should I go about doing this?
How should I go about doing this?
You can't (well, not reasonably). Ajax calls are asynchronous. By the time the ajax call completes, the call sortable made to change has long-since returned.
While you could (for now) make the ajax call synchronous, that's not usually a good idea as it locks up the UI of the browser during the call. jQuery will be removing the async flag in a future version.
So the correct thing to do is not rely on the result of the ajax call in change; come at the problem a different way (perhaps saving some state and restoring that state if required).
I need to check for a condition and run an AJAX call before sending other AJAX calls on my web app.
I was thinking about putting this AJAX call in a beforeSend on ajaxSetup with async: false (to prevent my initial call from running before this one has completed).
Something like this:
//I set an event that fires:
$.ajax({
type: "GET",
url: my_url,
beforeSend: function() {
//do something, like show a spinner loader gif
}
});
//Somehwere in my app I also have:
$.ajaxSetup({
beforeSend: function() {
if(x===1){
$.ajax({
type: "GET",
url: my_url/fetch_something,
async:false
});
}
}
});
Will my beforeSend on the first AJAX call overrun the one in the ajaxSetup? Is there a way to approach this better?
Better idea of my app:
I have a lot of Ajax calls through the app, each call sends a security hash on the headers to validate the user, these hashes have a time limit as well (both hash and time limit are saved in localStorage)
What I want from ajax setup (and the condition in it) is to check for the time limit - if time_limit < current_time than run an ajax call to refresh the users hash.
This isn't an exercise for 1 or 2 calls, I literally have 20+ growing Ajax calls on my app that make use of the users hash and it's very impractical to make this check in every single one of them.
UPDATED:
Have one method on an interval that sets up the 'session'/local-storage
var refreshing = false;
var intervalID;
$(document).ready(function(e){
var delay = 1234;
intervalID = window.setInterval(setupInterval, delay);
});
function setupInterval(){
refreshing = true;
$.ajax(URL).done(function(r) { //do stuff
setupStorage(r);
refreshing = false;
});
}
function setupStorage(info){
//setup whatever here
}
OLD:
Could you use some logic in your ready function to gate what you need to do?
So basically call one ajax call -> if false, just schedule your latter methods, otherwise run the setup one and on completion schedule the latter method.
Some pseudo-code:
var refresh = false;
$(document).ready(function(e){
$.ajax(URL).done( function(r) {
if(r) {
routeOne();
} else {
latter();
}
});
});
function routeOne(){
$.ajax(URL).done(function(r) { //do stuff
latter();
});
}
function latter(){
//All other ajax calls
}
I'll put some more thought into this let me finish my coffee first...
EDIT:
Based on your updated description could it be possible for you to schedule a setInterval to run the checking method/hash update on the time interval that you need, and is the time interval on your server static or variable? Facebook does this with a heartbeat, I've used this type of logic with some 'locking' functionality in a web-app. If you schedule the interval properly it should not interrupt any other ajax calls.
Try overriding $.ajax to make a "pre-call" before passing in your given query options:
var oldAjax = $.ajax;
$.ajax = function() {
var args = arguments;
oldAjax({
type: "GET",
url: "/echo/html/",
success: function(result){
// do something here to check result
// if result is good, do the request:
return oldAjax.apply($, args);
// if its bad, handle the error
}
});
}
Here's a fiddle to demonstrate: http://jsfiddle.net/NF76U/
I suggest the use of .done() ( $.Deferred object)
function AjaxCall() {
return //code of your ajax without async:false
}
function anotherAjaxCall{
return //code of you ajax call
}
AjaxCall.done(anotherAjaxCall);
Avoid using async:false it's a deprecated practice and it stucks browsers
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);
});
});