Reputation: 3074
I have a page where I fire an ajax request AND show a loading sign for the first 6 seconds after the user presses a button :
<button onclick="runLoader();"></button>
<script>
var startTime=(new Date).getTime();
function runLoader(){
runAjax();
var i=0;
var timer = setInterval(function(e){
i++;
//code for loading sign
if(i==3)
clearInterval(timer);
} ,2000);
}
function runAjax(){
$.ajax({
//
}).done(function(){
var timer2 = setInterval(function(){
var d = new Date();
var t = d.getTime();
if(t-startTime>=6000){
clearInterval(timer2);
// do X
}
},500);
}
}
</script>
I want to do action X only after both runLoader()
has run for 6 seconds and runAjax()
has resulted in a response, and no sooner.
Like, if runAjax() responds in 2 seconds, I still want to continue showing loading sign for 6 seconds and then perform X. And if the loading sign has shown for 6 seconds, I want to wait for runAjax() to return for as long as it takes.
But using the Date()
method is giving inaccurate results. For eg : It shows 7.765 s elapsed even when only 2 s have passed. I read somewhere I should use console.log(time)
for better accuracy, but it doesnt work in <=IE9.
Is there a better way to approach this problem ?
Note: I am using setInterval()
instead of setTimeout()
because the loading involves cycling through an array of 3 elements, "Fetching", "Processing" and "Loading" each shown for 2 seconds :)
Upvotes: 1
Views: 1147
Reputation: 27012
I would use deferred
s and $.when
:
function start(){
$.when(runLoader(), runAjax()).done(function() {
//both are now finished
});
}
function runLoader() {
//show loader here
var def = $.Deferred();
setTimeout(function() {
//hide loader here
def.resolve(true);
}, 6000);
return def.promise();
}
function runAjax() {
var def = $.Deferred();
$.ajax({...}).done(function(result) {
//handle response here
def.resolve(true);
});
return def.promise();
}
Upvotes: 8
Reputation: 5156
You can create a pre-caller function that is run on runLoader() and as callback of runAjax(), that will verify if the other action is complete, and then do action X. Example:
var ajaxDone = false;
var loaderDone = false;
function doActionX() {
//your action happens here
}
function tryToDoX() {
if (ajaxDone && loaderDone) {
doActionX();
}
}
function runLoader(){
loaderDone = false;
runAjax();
//show loading sign
setInterval(function(e){
//hide loading sign
clearInterval(timer);
loaderDone = true;
tryToDoX();
}, 6000);
}
function runAjax(){
ajaxDone = false;
$.ajax({
//whatever
}).done(function(){
ajaxDone = true;
tryToDoX();
}
}
It isn't necessary to make a recurring timeout and poll both statuses, because they only get completed once (in every run, i.e. booleans aren't set to false and true while waiting).
EDIT: This approach can be used to any asynchronous code that doesn't change status intermitently, even without jQuery.
Upvotes: 0
Reputation: 9224
I would set a flag to mark it as "ready". There may be better ways to handle this, but this is just off the top of my head.
<script>
function runLoader(){
runAjax();
var i=0;
var timer = setInterval(function(e){
i++;
//code for loading sign
if(i==3)
clearInterval(timer);
} ,2000);
}
function runAjax(){
var timeElapsed = false;
setTimeout(function(){timeElapsed = true}, 6000);
$.ajax({
//
}).done(function(){
var timer2 = setInterval(function(){
if(timeElapsed){
clearInterval(timer2);
// do X
}
},500);
}
}
</script>
Upvotes: 0