2013-08-11 8 views
6

Aby szybko wystrzelić zdarzenie keypress, chcę ograniczyć obsługę zdarzenia do maksimum raz na X sekund.Jak ograniczyć obsługę zdarzenia do jednego razu na X sekund za pomocą jQuery/javascript?

Już używam jQuery do obsługi zdarzeń, więc preferowane byłoby rozwiązanie bazujące na jQuery, choć również javascript wanilii jest w porządku.

  • This jsfiddle przedstawia naciśnięcie szybkiego wypalania bez żadnego ograniczenia na obsługę

  • This jsfiddle narzędzia ograniczające obsługi raz na 0,5 sekundy wanilii JS pomocą setTimeout()

pytanie jest

  1. Czy jQuery ma wbudowany sposób robienia tego? Nie widzę nic w .on()docs

  2. Jeśli nie, to czy istnieje lepszy wzorzec dla tej operacji w waniliowym JS niż użyłem w moim second jsfiddle example?

+0

Można rozważyć użycie zamiast keyup, chyba że masz jakiś powód chcąc się powtarza. – GreatBigBore

+8

https://code.google.com/p/jquery-debounce/ http://www.hnldesign.nl/blog/debouncing-events-with-jquery/ – zerkms

+0

@zerkms dzięki, naprawdę chciałem zrobić to w "czysta" jQuery bez wtyczek, ale to bardzo pomocne - rozważ promowanie, aby odpowiedzieć, abym mógł się upomnieć! – davnicwil

Odpowiedz

22

Czy jQuery ma wbudowany sposób robienia tego?

nr

Jeśli nie, to czy istnieje lepszy wzorzec dla tej operacji w waniliowym JS niż użyłem w moim drugim jsfiddle przykład?

Zamiast używać setTimeout i flag, można śledzić, kiedy dzwoniący był wywoływany po raz ostatni i wywoływać go tylko po upływie określonego czasu. Jest to określane jako throttling i istnieją różne sposoby na jego wdrożenie.

W najprostszej formie wystarczy zignorować każde wywołanie, które jest wykonywane w czasie lastCall + interval, tak aby miało miejsce tylko jedno połączenie w każdym interwale.

E.g.tutaj jest funkcja, która zwraca nową funkcję, która może być wywołana tylko raz co X milisekund:

function throttle(func, interval) { 
    var lastCall = 0; 
    return function() { 
     var now = Date.now(); 
     if (lastCall + interval < now) { 
      lastCall = now; 
      return func.apply(this, arguments); 
     } 
    }; 
} 

które można wykorzystać jako

$("#inputField").on("keypress", throttle(function(event) { 
    $("div#output").append("key pressed <br/>"); 
}, 500)); 

DEMO


Jak Esailija wspomina w his comment, może to nie jest dławienie, które potrzebujesz, ale rozwiązuje się podając. Jest to podobna, ale nieco odmienna koncepcja. Podczas gdy dławienie oznacza, że ​​coś powinno się zdarzyć tylko raz na każde x milisekundy, rozwodnienie oznacza, że ​​coś powinno wystąpić tylko wtedy, gdy nie wystąpiło w ostatnich x milisekundach.

Typowym przykładem jest wydarzenie scroll. Program obsługi zdarzeń przewijania będzie wywoływany bardzo często, ponieważ zdarzenie jest w zasadzie wyzwalane w sposób ciągły. Ale może chcesz uruchomić program obsługi tylko wtedy, gdy użytkownik przestał przewijać, a nie przewijać.

Prostym sposobem osiągnięcia tego celu jest wykorzystanie limitu czasu i anulować ją, jeśli ta funkcja jest ponownie wywoływany (a limit czasu jeszcze nie działać):

function debounce(func, interval) { 
    var lastCall = -1; 
    return function() { 
     clearTimeout(lastCall); 
     var args = arguments; 
     var self = this; 
     lastCall = setTimeout(function() { 
      func.apply(self, args); 
     }, interval); 
    }; 
} 

Wadą tej realizacji jest to, że ciebie nie może zwrócić wartości z obsługi zdarzenia (na przykład return false;). Być może istnieją implementacje, które mogą zachować tę funkcję (jeśli jest to wymagane).

DEMO

+1

Czy to nie jest dławienie? Myślę, że porzucenie oznacza ciągłe przestawianie czasu tak długo, jak połączenia przychodzą w ciągu pewnej ilości milisekund i tylko wykonają jedno połączenie w końcu, gdy wszystko się uspokoi. Może mam je w inny sposób ... – Esailija

+0

@Eailailija: Myślę, że masz rację. Myślałem, że dławienie spowoduje, że wszystkie połączenia będą w kolejce, zamiast ich ignorować, ale nie jestem teraz pewien. Może to jest mieszanka obu? –

+1

OK, wygląda na to, że to nie jest dławienie i nie wyłamywanie się. Zgodnie z tym wyjaśnieniem http://drupalmotion.com/article/debounce-and-throttle-visual-explanation: P, może dławienie ... Argh, ale zdecydowanie nie jest debouncing – Esailija

1

Nagraj, kiedy ostatnio przetwarzałeś wydarzenie, i za każdym razem, gdy dostaniesz wydarzenie, sprawdź, czy upłynął określony czas.

2

zrobiłbym to wydarzenie dławienia tak proste, jak to:

$("#inputField").on("keypress", function(event) { 
    var now = Date.now(); 
    var nt = $(this).data("lastime") || now; 
    if(nt > now) return; 
    $(this).data("lastime", now + 500); 
    $("div#output").append("key pressed <br/>"); 
}); 
Powiązane problemy