web-dev-qa-db-fra.com

Appels d'événements de la manette dans jQuery

J'ai un événement keyup lié à une fonction qui prend environ un quart de seconde.

$("#search").keyup(function() {
  //code that takes a little bit to complete
});

Lorsqu'un utilisateur tape un mot entier ou appuie autrement sur les touches rapidement, la fonction est appelée plusieurs fois de suite et leur exécution prend du temps.

Existe-t-il un moyen de limiter les appels d’événements afin que, s’il y en ait plusieurs successivement, ils ne déclenchent que celui qui a été appelé le plus récemment?

40
Peter Olson

Jetez un oeil à jQuery Debounce .

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

Voici une solution potentielle ne nécessitant pas de plugin. Utilisez un booléen pour décider de faire le rappel à la touche ou de le sauter.

var doingKeyup = false;

$('input').keyup(function(){
    if(!doingKeyup){
        doingKeyup=true;
        // slow process happens here
        doingKeyup=false;
    }
});
8
Nathan Manousos

Vous pouvez également utiliser l'excellente bibliothèque/ Underscore/_ .

Les commentaires dans answer de Josh, qui sont actuellement les plus populaires, demandent si vous devez vraiment étrangler les appels ou si vous voulez un débogueur. La différence est un peu subtile, mais Underscore a les deux: _.debounce(function, wait, [immediate]) et _.throttle(function, wait, [options]) .

Si vous n'utilisez pas encore Underscore, vérifiez-le. Il peut rendre votre code JavaScript beaucoup plus propre et il est suffisamment léger pour laisser une pause à la plupart des détracteurs de la bibliothèque.

3
Michael Scheper

Voici une façon propre de le faire avec 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);
1
AntonK

Deux petites implémentations génériques d’approches de limitation. (Je préfère le faire à travers ces fonctions simples plutôt que d'ajouter un autre plugin jquery)

  1. Attend quelque temps après le dernier appel

    Celui-ci est utile lorsque nous ne voulons pas appeler, par exemple, la fonction de recherche lorsque l'utilisateur continue à taper la requête

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. Les appels donnés ne fonctionnent pas plus souvent que le temps imparti

    Le suivant est utile pour vider les journaux

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

L'utilisation est très simple:

Le suivant attend 2 secondes après la dernière frappe dans le inputBox, puis appelle la fonction qui doit être limitée.

$("#inputBox").on("input", throttle(2000, function(evt) {
  myFunctionToThrottle(evt);
}));

Voici un exemple où vous pouvez tester les deux: clic (CodePen)

0
Max

Je suis tombé sur cette question en passant en revue les modifications apportées à zurb-foundation . Ils ont ajouté leur propre méthode de contrôle anti-rebond et de régulation. Il semble que ce soit le même que le jquery-debounce @ josh3736 mentionné dans sa réponse.

De leur site web: 

// 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));
0
th3byrdm4n