Uczymy się debounce. Na początku zdefiniuję, co przez to rozumiem, potem przykład plus mały bonus. Do dzieła.

Zdefinujmy debounce:

  • Jeżeli użytkownik wpisze w panel wyszukiwania literę 'a’ i się zatrzyma
    • funkcja wyszukaj podpowiedzi na literę 'a’ wykona się od razu
  • Jeżeli użytkownik wpisze w panel wyszukiwania literę 'a’, zatrzyma się na 5 sekund (albo 5 godzin) i dopisze 'n’ do a:
    • funkcja wyszukaj podpowiedzi na literę 'a’ wykona się od razu
    • funkcja wyszukaj podpowiedzi do 'an’ wykona się od razu
  • Jeżeli użytkownik w przeciągu 5 sekund wpisze w pasek wyszukiwania 'ann’:
    • funkcja wyszukaj podpowiedzi na literę 'a’ wykona się od razu
    • funkcja wyszukaj podpowiedzi dla 'an’ zakolejkuje się na następne 5 sekund
    • funkcja wyszukaj podpowiedzi dla 'ann’ anuluje 'wyszukaj dla an’ i kolejkuje 'wyszukaj ann’ na następne 5 sekund
  • Jeżeli użytkownik wpisze w ciągu 5 sekund 'ann’ potem dopisze 'a’ to:
    • funkcja wyszukaj podpowiedzi dla 'a’ ruszy natychmiast
    • funkcja wyszukaj podpowiedzi dla 'an’ zakolejkuje się
    • funkcja wyszukaj podpowiedzi dla 'ann’ anuluje poprzednią i zakolejkuje się
    • funkcja wyszukaj podpowiedzi dla 'anna’ ruszy natychmiast

To teraz piszemy funkcję:

  function debounceFunc(func, timeout = 3000){

    let timer = null;
    return (...args) => {

      if (timer === null) {
        
        func(...args);

        timer = setTimeout(() => { 
            timer = null
        }, timeout);

      } else {

        clearTimeout(timer);
        
        timer = setTimeout(() => { 
            timer = null
            func(...args); 
        }, timeout);
      }
     
    };
  }


  function search(term){
    console.log("Im searching " + term);
  }

  const debouncedSearch = debounceFunc(search, 5000);
  debouncedSearch("javascript");

Oczywiście te 5 sekund bardzo umowne. Aż takiego opóźnienia nie dajemy.

A teraz przykład jak NIE robić debounce:

function debounce_leading(func, timeout = 300){
  let timer;
  return (...args) => {
    if (!timer) {
      func.apply(this, args);
    }
    clearTimeout(timer);
    timer = setTimeout(() => {
      timer = undefined;
    }, timeout);
  };
}

Czy coś jest nie teges z logiką? Nie wiem, bo nie jest to zbyt czytelny kod, ale zakładam, że jeżeli nie działa jak throttle to jest to debounce, zgodnie z dowolną definicją.

To co jest w tym kodzie nie tak?

Mała podpowiedź:

 timer = undefined;

Nigdy, przenigdy nie dopisujmy undefined jako wartość zmiennej. Jedyny przykład zmiennej, która ma prawo być undefined:

let x;
console.log(x);
//undefined

Warunki dla if też powinny być bardziej dokładne, proszę spojrzeć na to:

let x = null;
let y;
let z = 0;

if(!x)
  console.log("null is not truthy");
if(!y)
  console.log("undefined is not truthy");
if(!z)
  console.log("0 is not truthy");

To zero jest szczególnie podstępne gdy chcemy sprawdzić, czy jakiś argument liczbowy (może być 0) został przekazany:

let x = null;
let optional1 = x || 1;
console.log(optional1);
//1

let y = 0;
let optional2 = y || 1;
console.log(optional2);
//1

W takich wypadkach lepiej używać bardziej dokładnych operatorów:

let x = null;
let optional1 = x ?? 1;
console.log(optional1);
//1

let y = 0;
let optional2 = y ?? 1;
console.log(optional2);
//0

No ale co ja tam wiem…