Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как сделать throttle функции

Короткий ответ

Throttle позволяет функции срабатывать не чаще одного раза за интервал и пропускает вызовы между ними:

function throttle(fn, ms) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= ms) {
      last = now;
      fn(...args);
    }
  };
}
 
const log = throttle((n) => console.log('call', n), 100);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
 
for (let i = 1; i <= 10; i++) {
  log(i);
  await sleep(30);
}

Результат:

call 1
call 4
call 8

При прокрутке

Событие scroll срабатывает десятки раз в секунду. Throttle не даёт обработчику тормозить страницу:

window.addEventListener('scroll', throttle(() => {
  backToTopButton.hidden = window.scrollY < 500;
}, 200));

Debounce или throttle

Debounce ждёт паузу и вызывает один раз в конце — подходит для полей поиска. Throttle вызывает регулярно, пока события идут, — подходит для прокрутки, изменения размера и движения мыши.

input.addEventListener('input', debounce(search, 300));
window.addEventListener('resize', throttle(updateLayout, 200));

Частая ошибка

Этот простой throttle теряет последний вызов. Если важно финальное состояние, например конечная позиция прокрутки, добавьте завершающий вызов по таймеру:

function throttle(fn, ms) {
  let last = 0;
  let timer;
  return (...args) => {
    const now = Date.now();
    clearTimeout(timer);
    if (now - last >= ms) {
      last = now;
      fn(...args);
    } else {
      timer = setTimeout(() => {
        last = Date.now();
        fn(...args);
      }, ms - (now - last));
    }
  };
}
 
const log = throttle((n) => console.log('call', n), 100);
log(1);
log(2);
log(3);

Результат:

call 1
call 3

Функции из этого ответа

  • setTimeout — Выполняет функцию один раз через заданное время.
  • Date.now — Возвращает текущее время как число миллисекунд.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.