В разработке на JavaScript часто возникает необходимость
контролировать частоту выполнения функций, особенно при работе с
событиями браузера, такими как scroll, resize,
input и mousemove. Для этих целей применяются
техники debounce и throttle, каждая из
которых решает разные задачи и имеет свои особенности.
Debounce — это техника, позволяющая вызвать функцию только после того, как определённое время прошло с момента последнего вызова. Другими словами, если событие повторяется слишком часто, функция будет вызвана только один раз, после того как поток событий остановится на заданный интервал.
Применение:
resize) для
перерасчёта макета.Пример реализации:
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Использование:
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce((event) => {
console.log('Поиск:', event.target.value);
}, 300));
Особенности:
immediate, позволяющую вызывать
функцию в начале, а не в конце периода задержки.function debounce(func, wait, immediate) {
let timeout;
return function (...args) {
const context = this;
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (callNow) func.apply(context, args);
};
}
Throttle ограничивает частоту вызова функции, гарантируя, что она будет выполнена не чаще одного раза в заданный промежуток времени. В отличие от debounce, функция вызывается регулярно, даже если события продолжают срабатывать.
Применение:
scroll).Пример реализации:
function throttle(func, limit) {
let lastFunc;
let lastRan;
return function (...args) {
const context = this;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(() => {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
// Использование:
window.addEventListener('scroll', throttle(() => {
console.log('Скролл с ограничением частоты');
}, 200));
Особенности:
| Параметр | Debounce | Throttle |
|---|---|---|
| Когда вызывается | После окончания серии событий | На регулярных интервалах |
| Цель | Игнорировать промежуточные события | Ограничить частоту вызова |
| Применение | Поиск, resize, ввод текста | Скролл, mousemove, анимации |
| Последний вызов | Всегда происходит после задержки | Может пропустить последний вызов |
Выбор между debounce и throttle зависит от задачи: если важен финальный результат после серии событий — debounce, если важна периодическая реакция — throttle.
Navigo — это лёгкий роутер для SPA, где debounce и throttle могут использоваться для оптимизации:
Пример: динамический поиск с debounce в Navigo:
const router = new Navigo('/');
function loadSearchResults(query) {
console.log('Загружаем результаты для:', query);
// fetch(`/search?q=${query}`) ...
}
const debouncedSearch = debounce(loadSearchResults, 300);
router.on('/search/:query', (params) => {
debouncedSearch(params.query);
}).resolve();
Пример: throttle для отслеживания скролла с маршрутизацией:
window.addEventListener('scroll', throttle(() => {
const position = window.scrollY;
if (position > 500) {
router.navigate('/long-scroll');
}
}, 200));
_.debounce, _.throttle) для готовых и
проверенных реализаций с расширенными опциями.Эти техники позволяют значительно повысить производительность SPA и улучшить пользовательский опыт при высокочастотных событиях.