Jeden z ważniejszych konceptów we frontendowym programowaniu w JavaScript, czyli throttle. Poznajemy czym jest i jak go używać.

Cóż, zasada jest prosta:

  • Funkcja throttle przyjmuje funkcję i opóźnienie
  • Gdy funkcja jest throttled sprawdzane jest, czy przez ostatnie n-sekund nie była wywoływana
  • Jeżeli przez ostatnie n-sekund funkcja nie była wywoływana, to się wywoła

Napiszmy sobie throttle:


function throttle(mainFunction, delay) {

    let timerFlag = null; 
  
    return (...args) => {
      
    if (timerFlag === null) { 

        mainFunction(...args); 

        //obsługa timerFlag
       }
    };
  }

Cóż, widzimy funkcję wyższego rzędu przyjmującą func i delay, domknięcie na zmienną timerFlag, zwrócenie funkcji, której dajemy argumenty i jeżeli timerFlag jest nullem to ją wywołujemy z argumentami.

Dla uproszczenia napiszmy sobie jeszcze funkcję once:

function oncify(mainFunction) {

    let executedFlag = false;

    return (...args) => {
      
    if (executedFlag === false) { 

        mainFunction(...args); 
        executedFlag = true;
       }
    };
  }

function sayHello(name) {
     console.log("Hello " + name);
  }
  
const helloOnce = oncify(sayHello);

helloOnce("John");
//Hello John

helloOnce("John");
//nic...

Tu zasada jest prosta – jeżeli kiedykolwiek wcześniej tę funkcję wywołano to nie wolno jej wywołać ponownie.

W throttle ma to wyglądać inaczej – jeżeli nie wywołano jej przez n-sekund to można ją wywołać:

function throttle(mainFunction, delay) {

    let timerFlag = null; 
  
    return (...args) => {
      
    if (timerFlag === null) { 

        mainFunction(...args); 

        timerFlag = setTimeout(() => { 
          timerFlag = null; 
        }, delay);      
      
       }
    };
  }

Czyli tak:

  • Bierz func i delay
  • Przez closure ustaw flag na null
  • Zwracaj funkcję, która przyjmuje dowolne argumenty
  • Jeżeli flaga jest nullem, wywołaj func z argumentami
  • Ustaw timeout na ponowne zanullowanie flagi
  • Do czasu zapełnienia nullem timerFlag będzie mieć zwracany przez setTimeout timerID…

Tyle tytułem throttle, ale jeszcze proponuję powrót do oncify i danie możliwości zwracania wartości (przy jednorazowym wywołaniu):

function oncify(mainFunction) {

    let executedFlag = false;
    let res = null

    return (...args) => {
      
    if (executedFlag === false) { 
        res = mainFunction(...args); 
        executedFlag = true;
       }
       return res;
    };
  }

  function sayHello(name) {
        console.log("Hello " + name);
        return 42;
  }
  

  const helloOnce = oncify(sayHello);

  helloOnce("John");
  //Hello John

  helloOnce("John");
  //nic...

  console.log(helloOnce("John"))
  //42