If I want to implement short polling like this:
function firstCall(){
$.ajax({
...
success: function(response){
if (response.OK == "OK"){
secondCall();
}else{
firstCall();
}
}
});
}
Will this be enough? or do I really need to surround the firstCall() in else clause with setTimeout ?Thanks
I recommend you to use a little timeout, because now you are creating a lot of traffic to your server. Ajax is fast and success will be executed very often.
So I recommend you to use setTimeout or setInterval instead!
This solution relies on the first call to be a success. If at any point in time your code doesn't "succeed" (perhaps there was a server hiccup?), your "polling" will stop until a page refresh.
You could use setInterval to call that method on a defined interval, which avoids this problem:
setInterval(function(){
$.ajax({}); // Your ajax here
}, 1000);
With both solutions, your server will be handling a lot of requests it might not need to. You can use a library like PollJS (shameless self plug) to add increasing delays, which will increase performance and decrease bandwidth:
// Start a poller
Poll.start({
name: "example_poller",
interval: 1000,
increment: 200,
action: function(){
$.ajax({}); // Your ajax here
}
});
// If you want to stop it, just use the name
Poll.stop("example_poller");
You need setTimeout() if you want to reduce requests to server
you'll need to setTimeout if you don't want to wait to user action or ajax response to trigger an event after a certain time, otherwise you may do wait for the ajax call success or error events.
Related
In Javascript, I have two asychronous requests for data:
$.getJSON('http://foo.com', fooQuery, fooSuccess(data));
$.getJSON('http://bar.com', barQuery, barSuccess(data));
and two callbacks to process the received data:
fooSuccess(data) { // Stuff }
barSuccess(data) { // More Stuff }
How do I ensure barSuccess is executed only after fooSuccess completes?
Notes:
I want to keep the data requests as they are: asynchronous and non-blocking (since server responses may take a while).
But, I want the callbacks that process the data to be executed sequentially. That is, I do not want to execute barSuccess until fooSuccess completes.
Thanks so much for your wisdom and help!
Here is how you would do it using the jQuery deferred object that is returned by ajax requests.
var fooDfd = $.getJSON('http://foo.com', fooQuery);
var barDfd = $.getJSON('http://bar.com', barQuery);
fooDfd.then(function(fooData){
fooSuccess(fooData);
barDfd.then(barSuccess);
});
The best way would be to utilize the jQuery when().done() functionality like this:
$.when(
$.getJSON('http://foo.com', fooQuery, fooSuccess(data)),
$.getJSON('http://bar.com', barQuery, barSuccess(data))
).done(function(arg1, arg2){
fooSuccess(arg1);
barSuccess(arg2);
});
This allow simultaneous execution of the AJAX requests and guaranteed execution of the done() function once all requests has successfully completed.
I'm follow this very interesting post from a half an hour ago, when appear the elegant solution presented by #Mike Brant I quickly was to dive in the jquery library to see how the magic is made. Don't you? I recommend, is very interesting!
BTW I think we don't need all that magic, not in this case, we have two asynchronous calls handlers(functions), no matter which end first, we need to know when the second end, then all we need is a third function that will be called by the two handlers and act when all the data is ready. I know this approach will vaste four or five lines more of code than the elegant jquery solution, but at the end our brain and soul will be in better condition. Sorry my english.
Put the barSuccess call in the fooSuccess success callback.
fooSuccess(data){
jQuery.ajax({
data: data,
success: function(response){
barSuccess(data) //should still be in scope, I think?
}
}
}
I have a jQuery POST function inside of a loop (multiple post calls).
For some reason, jQuery is posting, but not returning all the data until the loop ends and parsing all the results at once.
FOREACH arg_value IN args
{
console.log('Do stuff');
$.post('https://blah.com/xml.php',
{arg: arg_value},
function(xml) {
$(xml).find('tag').each(function() {
console.log('Do more stuff');
});
});
}
The output of this is...
Do stuff
Do stuff
Do stuff
Do more stuff
Do more stuff
Do more stuff
It seems like jQuery is caching the result or not executing it until the end.
I'm expecting...
Do stuff
Do more stuff
Do stuff
Do more stuff
Do stuff
Do more stuff
Is there an option to tell jQuery to pause execution until there is a result from the AJAX? It appears to be running asynchronously as usual, but I don't want that in this case.
A AJAX call is asynchronous. This means your callback:
function(xml) {
$(xml).find('tag').each(function() {
console.log('Do more stuff');
});
}
Only gets executed when the server returns a response.
Meanwhile, your for-each loop will keep running, and logging Do stuff.
Unless you're doing crazy stuff in your loop, the loop will be faster than the server response
Like Jan Dvorak mentioned, Even if you do crazy stuff, the AJAX callbacks will wait for the loop to finish, resulting in Do stuff always appearing before any of the AJAX responses.
Your ajax call is asyncronous, which means that the ajax call is fired off, then the execution flow of further code continues. It does not wait around for the response. When the response is finally received, the callback is executed.
What you could do is to have your ajax calls all stack up in a queue and as each response is received, fire off the next call in the queue. This would achieve your diesired effect, whereby the next ajax call is not sent until the current one is done.
If you have many calls, this would be much slower than firing them all off as soon as they are needed because browsers can easily handle multiple ajax calls at the same time.
$.post() is async call...will not work in loops the way u want..To get the way u want..here is the solution..
var i=0;
callbackfunc(i) {
console.log('Do stuff');
$.post('https://blah.com/xml.php',
{arg: args[i]},
function(xml) {
$(xml).find('tag').each(function() {
//something related to xml data
});
console.log('Do more stuff');
i++;
if(i<args.length)callbackfunc(i)
}
});
}
take care of variables..may create closures here...
you are asynchronous here, if you want to do that probably the easiest way to achieve this is to use async.js
Is there an event in javascript that I could bind some sort of listener to that will tell me when all javascript/jQuery/Ajax is done executing on the page? The page will not be loading/unloading/reloading, etc between the time the execution begins and the time that I need the listener to "listen", so those events don't work. The page literally is not doing anything. The button is clicked and some javascript functions fire which contain Ajax calls to web services. After all have finished, I want to change window.location. But window.location is changing before the web services have finished in my case.
Currently using setTimeout to achieve this, but as sometimes the code needs more time to run than normal, sometimes the window.location is firing before all the other javascript has finished. Simply put
<input type = "button"... onclick="doThis();";
function doThis() {
try{
//Contains AJAX calls to web services which is mainly what screws up my timing since it may still be trying to execute stuff when the redirect statement happens
}
catch (e) {
}
//Currently doing setTimeout(redirect, 10000);
//Would like to simply detect when all of the above is done and then redirect.
}
Edit: Left out a crucial piece of info. The AJAX calls are in a for loop. The use of variables and success callbacks hasn't been working so well for me as by the time my success callback is executing, my variables have taken on new values in the for loop.
What you are trying to achieve is a classical concurrent programming problem. It is solved by the use of a barrier.
To put it simply, you need to:
Count how many calls you've done.
Set a callback on all AJAX completion events.
Make that callback decrement the number of calls.
The callback checks whether the number of calls has reached zero or not. If yes, then your final code (here, redirect) is called.
The actual implementation is left as an exercise to the reader :)
Hint: embed AJAX calls into a function that handles all counter incrementation and callback setting.
What I do:
Create a variable that represents the number of outstanding AJAX calls.
Before making an AJAX call, increment the variable.
At the end of the code that completes an AJAX call, call a function (e.g. ajaxComplete).
ajaxComplete should decrement the count. When it reaches zero, you know all your calls are complete.
Assuming you're using jQuery.ajax, it sounds like you're looking for ajaxStop.
Why don't you try using something like the Underscore library's after function in the callbacks?
var done = _.after(3, function() {
window.location = 'http://example.com';
});
$.ajax({
url: '/tic',
success: function() {
done();
}
});
$.ajax({
url: '/tac',
success: function() {
done();
}
});
$.ajax({
url: '/toe',
success: function( data ) {
done();
}
});
You should check for the response from AJAX call, and only in that response do redirect. This way you will avoid doing redirect while AJAX was still executing.
How to send Ajax request on every 1s using JQuery ?
You probably don't want to send a request every second as David already noted.
Therefore, using setInterval is a bad idea.
Instead consider doing something like this:
function doAjax() {
$.ajax({
...
complete: function() {
setTimeout(doAjax,1000); //now that the request is complete, do it again in 1 second
}
...
});
}
doAjax(); // initial call will start rigth away, every subsequent call will happen 1 second after we get a response
you can use setInterval, but setInterval ist not part of jQuery:
setInterval(function() {
$.get(...);
}, 1000);
The interval 1 sec is small enough and it can be that you will start the second request before you receive response to the first request. So you should either start the next request after receiving of the previous one (see the suggestion of Martin Jespersen) or save jqXHR from the previous $.ajax request in a variable and use it to abort the previous request (see here an example)
setInterval(myAjaxCall, 1000);
Obviously in the function myAjaxCall() you will do all you ajax stuffs with jquery.
if you use setInterval method, you may crush the browser, because setInterval is not waiting for ajax function to complete, if server is running slow or user's connection speed is low this may be cause running multiple ajax requests at the same tme
I have a function called:
function callAjax(url, data) {
$.ajax(
{
url: url, // same domain
data: data,
cache: false,
async: false, // use sync results
beforeSend: function() {
// show loading indicator
},
success: function() {
// remove loading indicator
}
}
);
}
In the code, I call "callAjax" X number of times and I want to update the data synchronously. It is done as expected, but one problem: the loading item doesn't show in beforeSend function. If I turn async to true, it works but the updates aren't synchronously done.
I've tried several things with no success. I tried putting the loading indicator before the ajax call like this:
function callAjax(url, data) {
// show loading div
$.ajax(
{
// same as above
}
);
}
But for some reason it doesn't want to show the loading indicator. I notice a strange behavior when I put an "alert" in the beforeSend and the loading indicator appears in that case, but I rather not pop up a message box.
Got any ideas?
Making a synchronous call like that is like putting up an "alert()" box. Some browsers stop what they're doing, completely, until the HTTP response is received.
Thus in your code, after your call to the "$.ajax()" function begins, nothing happens until the response is received, and the next thing as far as your code goes will be the "success" handler.
Generally, unless you're really confident in your server, it's a much better idea to use asynchronous calls. When you do it that way, the browser immediately returns to its work and simply listens in the background for the HTTP response. When the response arrives, your success handler will be invoked.
When you do the blocking I/O the program is halted until the the input is received, in JS words when doing a synchronous call, the program halts and browser window freezes (no painting can be done) until the response is received. In most cases doing syncronus calls and any kind of blocking I/O can be avoided. However imagine your doing a progress bar in java or any other programming language, you have to spawn a different thread to control the progress bar, I think.
One thing to try in your case, is to call the ajax call after a time delay
//loading div stuff,
//if your doing some animation here make sure to have Sufficient
//time for it. If its just a regular show then use a time delay of 100-200
setTimeout( ajaxCall, 500 );
EDIT ajaxcall in setTimeout, Example
This is what you are looking for - .ajaxStart()
It will be triggered when any ajax event starts
http://api.jquery.com/ajaxStart/
They even give a specific example similar to what you are trying to accomplish:
$("#loading").ajaxStart(function(){
$(this).show();
});
You can then use the .ajaxStop() function
$("#loading").ajaxStop(function(){
$(this).hide();
});