Reputation: 17421
I have an asynchronous Ajax function which runs a command string at the server side and returns the result to the client. It calls a callback to process the result.
function ajaxCall(commandStr,callback){
var url=......//make a url with the command string
jquery.get(url,function(result){
//process the result using callback
callback(result);
});
}
The asynchronous call (ajaxCall) may take a while to be finished but I want it to do the same command after an interval (1000ms).
I want to write a function that is like this:
function ajaxCallRepeated(interval,commandStr,callback)
I tried closures like this:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(param1,param2,param3){
return (function(){
ajaxCall(param2,function(out,err){
if(param3)param3(out,err);
var functRef = callLater(param1,param2,param3);
setTimeout(functRef, interval);
});
});
}
//the first call
var functRef = callLater(interval,commandStr,callback);
setTimeout(functRef, interval);
}
Then I call it like this:
ajaxCallRepeated(2000,"ls",function(result){
alert(result);
});
But it only runs the command 2 times. How can I write a function that will reschedule itself after it is called as a callback of an asynchronous function?
PS. I want to fire another Ajax call after the previous one is finished. Also, it worth to mention that axashCallRepeated() will be called with various parameters, so several Ajax calls are running in parallel, but for each commandStr, there is only one Ajax call going on, and after the Ajax call returns, another one will be fired after X seconds.
Upvotes: 0
Views: 314
Reputation: 17166
It becomes easier to reason about if you separate things up a bit.
For example, the repetition logic doesn't have to know about AJAX or callbacks at all:
function mkRepeater(interval, fn, fnScope, fnArgs) {
var running;
function repeat() {
if (!running) return;
fn.apply(fnScope, fnArgs);
setTimeout(repeat, interval);
}
return {
start: function() { running = true; repeat(); },
stop: function() { running = false; }
};
}
You can use it like this:
var r = mkRepeater(2000, ajaxFunction, this, ["getStuff", callbackFn]);
r.start();
...
r.stop();
Upvotes: 0
Reputation: 17421
The key to solve this problem is to save a reference to the closure itself and use it when scheduling the next call:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(_interval,_commandString,_callback){
var closure=(function(){
ajaxCall(_commandString,function(out,err){
if(_callback)_callback(out,err);
setTimeout(closure,_interval);
});
});
return closure;
}
//now make a closure for every call to this function
var functRef = callLater(interval,commandString,callback);
//the first call
functRef();
}
Upvotes: 0
Reputation: 7546
I would not use setTimeout to trigger the second Ajax call ! Because you never know how long it will take and if it's finished !
As far as you tagged your question right and you ARE using jquery you should consider something like this:
$.ajax({
type: 'POST',
url: url,
data: data,
success: function(){
// The AJAX is successfully done, now you trigger your custom event:
$(document).trigger('myAjaxHasCompleted');
},
dataType: dataType
});
$(function(){
//somehwere in your document ready block
$(document).on("myAjaxHasCompleted",function(){
$.ajax({
//execute the second one
});
});
});
So this would ensure that the ajax post is DONE and was successful and now you could execute the second one. I know its not the exact answer to your question but you should consider on using something like this ! Would make it safer I guess :-)
Upvotes: 1