开发者

Throttle event calls in jQuery

开发者 https://www.devze.com 2023-04-04 04:05 出处:网络
I have a keyup event bound to a function that takes about a quarter of a second to complete. $(\"#search\").keyup(function() {

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 mos开发者_如何学Ct recently called?


Take a look at jQuery Debounce.

$('#search').keyup($.debounce(function() {
    // Will only execute 300ms after the last keypress.
}, 300));


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;
    }
});


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.


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);


Two small generic implementations of throttling approaches. (I prefer to do it through these simple functions rather than adding another jquery plugin)

  1. 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);
  }
}
  1. 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)


I came across this question reviewing changes to zurb-foundation. They've added their own method for debounce and throttling. It looks like it might be the same as the jquery-debounce @josh3736 mentioned in his answer.

From their website:

// Debounced button click handler
$('.button').on('click', Foundation.utils.debounce(function(e){
  // Handle Click
}, 300, true));

// Throttled resize function
$(document).on('resize', Foundation.utils.throttle(function(e){
  // Do responsive stuff
}, 300));


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
0

精彩评论

暂无评论...
验证码 换一张
取 消