Reputation: 142921
I have a keyup
event bound to a function that takes about a quarter of a second to complete.
$("#search").keyup(function() {
//code that takes a little bit to complete
});
When a user types an entire word, or otherwise presses keys rapidly, the function will be called several times in succession and it will take a while for them all to complete.
Is there a way to throttle the event calls so that if there are several in rapid succession, it only triggers the one that was most recently called?
Upvotes: 46
Views: 39807
Reputation: 411
Two small generic implementations of throttling approaches. (I prefer to do it through these simple functions rather than adding another jquery plugin)
Waits some time after last call
This one is useful when we don't want to call for example search function when user keeps typing the query
function throttle(time, func) {
if (!time || typeof time !== "number" || time < 0) {
return func;
}
var throttleTimer = 0;
return function() {
var args = arguments;
clearTimeout(throttleTimer);
throttleTimer = setTimeout(function() {
func.apply(null, args);
}, time);
}
}
Calls given function not more often than given amount of time
The following one is useful for flushing logs
function throttleInterval(time, func) {
if (!time || typeof time !== "number" || time < 0) {
return func;
}
var throttleTimer = null;
var lastState = null;
var eventCounter = 0;
var args = [];
return function() {
args = arguments;
eventCounter++;
if (!throttleTimer) {
throttleTimer = setInterval(function() {
if (eventCounter == lastState) {
clearInterval(throttleTimer);
throttleTimer = null;
return;
}
lastState = eventCounter;
func.apply(null, args);
}, time);
}
}
}
Usage is very simple:
The following one is waiting 2s after the last keystroke in the inputBox and then calls function which should be throttled.
$("#inputBox").on("input", throttle(2000, function(evt) {
myFunctionToThrottle(evt);
}));
Here is an example where you can test both: click (CodePen)
Upvotes: 1
Reputation: 7048
You could also use the excellent Underscore/_ library.
Comments in Josh's answer, currently the most popular, debate whether you should really throttle the calls, or if a debouncer is what you want. The difference is a bit subtle, but Underscore has both: _.debounce(function, wait, [immediate])
and _.throttle(function, wait, [options])
.
If you're not already using Underscore, check it out. It can make your JavaScript much cleaner, and is lightweight enough to give most library haters pause.
Upvotes: 6
Reputation: 2310
Here's a clean way of doing it with JQuery.
/* delayed onchange while typing jquery for text boxes widget
usage:
$("#SearchCriteria").delayedChange(function () {
DoMyAjaxSearch();
});
*/
(function ($) {
$.fn.delayedChange = function (options) {
var timer;
var o;
if (jQuery.isFunction(options)) {
o = { onChange: options };
}
else
o = options;
o = $.extend({}, $.fn.delayedChange.defaultOptions, o);
return this.each(function () {
var element = $(this);
element.keyup(function () {
clearTimeout(timer);
timer = setTimeout(function () {
var newVal = element.val();
newVal = $.trim(newVal);
if (element.delayedChange.oldVal != newVal) {
element.delayedChange.oldVal = newVal;
o.onChange.call(this);
}
}, o.delay);
});
});
};
$.fn.delayedChange.defaultOptions = {
delay: 1000,
onChange: function () { }
}
$.fn.delayedChange.oldVal = "";
})(jQuery);
Upvotes: 2
Reputation: 144912
Take a look at jQuery Debounce.
$('#search').keyup($.debounce(function() {
// Will only execute 300ms after the last keypress.
}, 300));
Upvotes: 70
Reputation: 19863
Something like this seems simplest (no external libraries) for a quick solution (note coffeescript):
running = false
$(document).on 'keyup', '.some-class', (e) ->
return if running
running = true
$.ajax
type: 'POST',
url: $(this).data('url'),
data: $(this).parents('form').serialize(),
dataType: 'script',
success: (data) ->
running = false
Upvotes: -4
Reputation: 13848
Here is a potential solution that doesn't need a plugin. Use a boolean to decide whether to do the keyup callback, or skip over it.
var doingKeyup = false;
$('input').keyup(function(){
if(!doingKeyup){
doingKeyup=true;
// slow process happens here
doingKeyup=false;
}
});
Upvotes: 13