Detaljno o Javascript Debounce i Throttle

. . .
image

Postoje mnogi odgovori na ovu temu koji se kreću po internetu, ali mnogi od njih čine ga komplikovanim iz nekog razloga prilikom objašnjavanja. To ne bi trebalo biti tako teško razumjeti pa ću pokušati ispuniti praznine za ovu temu. Također sam primijetio da slike mogu pomoći pri pokušaju razumijevanja stvari,tako da ču koristiti jednostavne primjere da objanism debounce i throttle u JavaScript.

Šta je debounce? ⚽

To je programski način koji koristimo da određeni taskovi ne pozivaju stalno. Ustvari zabranimo da se izvršavaju određene akcije jedna za drugom. I to uspjevamo tako što odgodimo izvršavanje akcija, i svaki put kada pokušamo da izvršimo akciju odgodimo je za odredjeno vrijeme, i prethodna akcija se ukloni tako da nebi izvršili svaku akciju, nego samo posljednju.

Ispod je slika koja pokazuje debouncing:

alt

Drawing by Fatima Trtak

Kao što vidite, ako kliknemo dugme više puta, nečemo izvršiti akciju koju dugme poziva sve dok ne prestanemo kliktati na dugme, i dok ne prodje određeno vrijeme koje smo zadali mi. Kada vrijeme prođe. izvršimo akciju. Ispod je primjer kako to možemo napisati u Javascript:

debounce.js
1const debounce = (fn, delay) => {
2 let timeoutID;
3
4 return function (...args) {
5 if (timeoutID) {
6 clearTimeout(timeoutID);
7 }
8
9 timeoutID = setTimeout(() => {
10 fn(...args);
11 }, delay);
12 };
13};
14
15document.getElementById('btn').addEventListener(
16 'click',
17 debounce((e) => {
18 console.count('click');
19 }, 1000)
20);
index.html
1<button id="btn">SUBMIT</button>

Ovdje imamo event listener na dugmetu sa id "btn". Svaki put kada kliknemo na to dugme, pozvat će se akcija koja će upisati rijeć "click" u konzolu. Kada kliknemo na to dugme pozivamo funkciju da uradi debounce i proslijedimo joj dva paremetra. Prvi parametar je funkcija koja će se izvršiti nakon što prodje vrijeme, a drugi parametar je vrijeme koje čekamo da prođe do idućeg klika na dugme. Svaki put kad je debounce funckija pozvana, kreira se varijabla timeoutID koja će čuvati vrijednost od setTimeout. Ta vrijednost nam treba jer svaki put kliknemo na dugme nova vrijednost setTimeout će biti kreirana, a prethodnu setTimeout čemo obrisati, tako da nam ne budu izvršene sve funckije osim posljednje koje kreiramo nakon klika na dugme. Onda vračamo funckiju koja se izvršava nakon svakog klika. Unutar funckije prvo provjeramo da li več postoji setTimeout, ako ima prvo je obrišemo i onda dodamo timeoutID novoj setTimeout koja će čekati da prođe vrijeme koje smo proslijedili ili dok ne kliknemo ponovno na dugme.

Nakon što vrijeme prođe, izvršit će se funckija koju smo poslali debounce, u našem slučaju to je console.count('click'). Ispod imamo komponentu na kojoj možete probati i vidjeti šta se dešava kada imamo debounce i kada nemamo, kliknite na oba dugmeta i vidite kako se vrijednosti mijenjaju:

Normal

{
  "requests": 0
}

Debounce

{
  "requests": 0
}

Kao što možete vidjeti, imamo mnogo manje klikova na debounced dugmetu nego na normalnom dugmetu. Ovo može biti korisno u aplikacijima gdje možda imate submit dugme za plačanje, i ako korisnik slučajno klikne dugme dva puta za redom, a nismo hendlali te klikove, mogu se poslati dva zahtjeva za plačanje i oduzet će se dupla suma sa računa korisnika od one koja je prikazana na aplikaciji. Debounce je posebno koristan kada se koristi pretraživanje, ako ste implementirali reaktivano pretraživanje, debounce može pomoći da se pošalje zahtjev tek kada se završi kucanje umjesto da se šalje nakon svakog slova.

Šta je throttle ? 🏍

Za razliku od debounce, throttle se izvršava između vremenskih intervala, znači kada kliknemo na dugme prvi put, odmah se izvrši akcije, i ako nastavimo kliktati na dugme, throttle će se izvršavati nakon svakog vremenskog intervala koje smo mi postavili. Ispod je slika koja prikazuje to ponašanje:

alt

Drawing by Fatima Trtak

Možete vidjeti na ovoj slici ( nadam se 😊) da kada kliknemo na dugme izvrši se akcija, i onda ako nastavimo kliktati, neće se ništa desiti sve dok vremenski interval ne prođe i onda će se akcija opet izvršiti. Ako smo uporni i nastavimo kliktati na dugme akcija će se izvršavati svaki put kad vremenski interval prođe. Evo primjer kako to možemo uraditi u JavaScript:

throttle.js
1const throttle = (fn, delay) => {
2 let last = 0;
3 return (...args) => {
4 const now = new Date();
5 if (now - last < delay) {
6 return;
7 }
8 last = now;
9 return fn(...args);
10 };
11};
12
13document.getElementById('btn').addEventListener(
14 'click',
15 throttle((e) => {
16 console.count('click');
17 }, 2000)
18);
index.html
1<button id="btn">SUBMIT</button>

Kao i sa debounce primjerom, imamo dugme u Html sa id "btn", i imamo throttle funkciju koja će biti pozvana na svaki klik. Onda ćemo kreirati varijablu gdje će se držati vrijednost od zadnje izvršene akcije. U slijedećem koraku, šaljemo nazad funkciju koja ce biti izvršena na svaki klik, i unutar te funkcije provjeravamo da li je prošao vremenski interval od posljednjeg klika. Ako je interval manji od zadanog vremena, nećemo raditi ništa, ali ako nije manji, dodamo novo vrijeme koje ćemo porediti sa idućim klikovima.Ako je vremenski interval prošao izvršavamo funkciju u našem slučaju (console.count('click')).ISto vrijedi i za pretraživanje, ukoliko unosimo neki tekst, throttle će se izvršavati svaki put kad interval prodje. Primjer ispod prikazuje normalno dugme i pretraživanje i sa throttle, pokušaj i prati šta se dešava:

Normal

{
  "requests": 0
}

Throttle

{
  "requests": 0
}

Nadam se da ste probali primjere iznad, i vidjeli ponašanje throttle, i da ste vidjeli razliku throttle i debounce. Throttle se ne koristi mnogo u praksi, ali dobro ga je znati, i ko zna mozda je on bolje rešenje za tvoj projekat nego debounce.

Zaključak

Nije bilo teško zar ne ? Malo je zbunjujuće, ali sa crtežima i interaktivnim primjerima lakše je za shvatiti. Debounce se često koristi i sada se može koristiti još više 😉. U postu smo vidjeli sta su debounce i throttle u JavaScript, gdje se mogu koristiti i kako radi. Ako si React developer, bit će ti drago da čuješ da planiram napraviti post o Debounce i Throttle u Reactu koristeći hooks, koji su drugaćiji poredeći sa JavaScript. Isto ako možete da podijelite stranicu i ovaj post sa drugima, pa da i oni mogu imati koristi od ovoga.