Reputation: 1362
In my fiddle I have following function that is called trice (to simulate the user starting it three times in quick succession)
https://jsfiddle.net/tvs1zdw9/1/
function test(){
var r = $.Deferred();
//simulate ajax call that loads data and takes 2 seconds
setTimeout(function(){
r.resolve();
count++;
$('#here>i').html(count);
},2000);
return r;
}
Goal: No matter how quickly the user keeps pressing the button I always want to wait until the function completes until it is run again.
I have already added a deferrer (r) which gives an indication to when the function is done with following code:
test().done(function(){
console.log('done running function');
});
Example:
I found the jQuery queue functionality but it seems it is only for functions chained to items in the DOM ...perhaps I do not understand it fully. Here: https://api.jquery.com/queue/
Can anyone help me build up a queue and then go through it after each function has completed?
Upvotes: 0
Views: 1492
Reputation: 19288
The code can be very simple, even elegant, if you implement :
First, a reusable function that forms a private queue and returns a function by which items may be added to the queue.
function AsyncQueue(stopOnError) {
var p = $.when(); // a resolved promise, which acts as the seed of a .then() chain (ie a "queue").
return function(fn) {
p = p
.then(null, function() { if(!stopOnError) return $.when(); }) // prevent propagation of a previous error down the chain.
.then(fn);
return p;
}
}
With this, the queue (the promise chain) will "self-administer" so the need for running
and runQueue()
disappears.
Now you can write :
function goodDelay() { // simulate a successful request
return $.Deferred(function(dfrd){ setTimeout(dfrd.resolve, 1000); });
}
function badDelay() { // simulate a failed request
return $.Deferred(function(dfrd){ setTimeout(dfrd.reject, 1000); });
}
var queue = AsyncQueue(false); // `queue` is a function with its own private .then chain.
queue(goodDelay).then(successHandler, errorHandler);
queue(badDelay).then(successHandler, errorHandler);
queue(goodDelay).then(successHandler, errorHandler);
function successHandler() {
console.log('success:');
}
function errorHandler() {
console.log('error:');
}
stopOnError
works as follows :
DEMO with stopOnError
false
DEMO with stopOnError
true
Upvotes: 1
Reputation: 1362
Solution: https://jsfiddle.net/jqqmrv4L/1/
I have created a variable queue
var queue = [];
When the function is called before it is completed I will push to queue.
var count = 0;
var running = false;
var queue = [];
var test = function(){
var r = $.Deferred();
if(!running){
running = true;
//simulate ajax call that loads data and takes 2 seconds
setTimeout(function(){
r.resolve();
count++;
$('#here>i').html(count);
running = false;
},2000);
} else {
console.log('called whilst running');
queue.push('234');
}
return r;
}
Then I have another function to handle the queue which is called after the initial function has completed like so:
test().done(function(){
console.log('done running function, checking queue');
runqueue();
});
And here the final "runqueue" function that handles the queue:
function runqueue(){
if(queue.length){
console.log('queue has!', queue.length);
//runqueue();
test().done(function(){
console.log('queue item completed');
queue.splice(0,1); //delete this because it has ran
//runqueue();
});
} else {
console.log('queue done');
}
}
Upvotes: 0