So, I\'ve searched for this high and low and maybe I\'m just having trouble understanding jQuery\'s deferred function or I\'m completely on the wrong track. So any help woul
Make a global variable(boolean), in this case called queue. If queue is false, set it to true and begin executing the code you want to run. When that code finishes, set queue back to false. Otherwise, if queue was true, just recursively call _this.messager()
until queue is set back to false, which would mean that the code is finished running.
fadeIn()
and fadeOut()
can take callbacks as the final argument, so I'm utilizing that here.
(function ( $ ) {
var queue = false;
$.fn.messager = function(message, effect, speed) {
var _this = $(this);
if (!queue) {
queue = true;
_this.fadeOut(speed, function() {
_this.text(message);
_this.fadeIn(speed, function() {
queue = false;
});
});
} else {
_this.messager(message, effect, speed);
}
return this;
};
}( jQuery ));
$('#messageBox').messager('One', 300);
$('#messageBox').messager('Two', 300);
$('#messageBox').messager('Three', 300);
This typically results in:
Uncaught RangeError: Maximum call stack size exceeded
Here we create a second variable called counter to keep track of how many times 'messager' is called recursively and doesn't exceed the limit specified in the options. I set a default of 50, which can be overwritten by the options parameter.
In addition, we've separated out the code that you want to run. This could even be multiple functions that call each other, the important bit is making sure that when your code is finished running, you set queue to false rather than returning false and setting queue to the result of the function. Setting it to the result of the function just makes it undefined until the function finishes returning. We want it to remain as true until the code is finished executing.
This example also throttles the recursive calling so that it's only called once every 100 milliseconds, although that too can be overwritten with whatever value you like (in milliseconds) via the options parameter.
(function( $ ) {
var queue = false;
var counter = 0;
$.fn.messager = function(message, effect, speed, options) {
var _S = $.extend({
throttle: 100,
counter: 50
}, options);
var _this = $(this);
counter += 1;
function codeToRun() {
_this.fadeOut(speed, function() {
_this.text(message);
_this.fadeIn(speed, function() {
queue = false;
});
});
}
if (!queue) {
queue = true;
codeToRun();
counter = 0;
} else {
if (counter < _S.counter) {
setTimeout(function() {
_this.messager(message, effect, speed);
}, _S.throttle);
}
}
return this;
};
})( jQuery );
$('#messageBox').messager('One', 300);
$('#messageBox').messager('Two', 300);
$('#messageBox').messager('Three', 300);
For some reason, calling methods on $(this)
directly gives me:
[Window, jquery: "1.11.0", constructor: function, selector: "", toArray: function, get: function…]
But storing $(this)
in a variable and calling methods on that variable gives me the correct element:
[div#messageBox, selector: "#messageBox", context: document, jquery: "1.11.0", constructor: function, toArray: function…]