Как сделать 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 — Возвращает текущее время как число миллисекунд.