В JavaScript при работе с динамическими событиями, такими как
scroll, resize, mousemove или
input, часто возникает проблема чрезмерного количества
вызовов обработчиков. Если не контролировать частоту вызова функции,
производительность страницы может сильно пострадать. Для решения этой
задачи используются техники throttle и
debounce.
Debounce позволяет ограничить вызов функции до момента, когда события перестанут происходить в течение определённого времени. То есть функция будет вызвана только один раз после «задержки», независимо от того, сколько раз срабатывало событие за этот промежуток.
Пример реализации debounce:
function debounce(func, wait) {
let timeout;
return function(...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
Применение:
window.addEventListener('resize', debounce(() => {
console.log('Окно изменено');
}, 300));
В этом примере функция console.log будет вызвана только
один раз через 300 мс после последнего события resize.
Особенности debounce:
Throttle ограничивает частоту вызова функции, позволяя ей выполняться не чаще, чем один раз за указанный интервал времени. Это особенно важно для непрерывных событий, где важно реагировать на каждое изменение, но без перегрузки.
Пример реализации throttle:
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(function() {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
Применение:
window.addEventListener('scroll', throttle(() => {
console.log('Прокрутка страницы');
}, 200));
В этом примере сообщение будет выводиться не чаще одного раза в 200 мс, даже если пользователь быстро прокручивает страницу.
Особенности throttle:
scroll,
mousemove и анимаций.| Параметр | Debounce | Throttle |
|---|---|---|
| Цель | Выполнение функции после прекращения события | Выполнение функции через фиксированные интервалы времени |
| Пример событий | input, keyup, поиск |
scroll, mousemove, resize |
| Частота вызовов | Один раз после паузы | Регулярно, через заданный интервал |
| Производительность | Минимизирует нагрузку при частых событиях | Баланс между отзывчивостью и нагрузкой |
| Опция «leading» | Да | Да, зависит от реализации |
Библиотека Headroom.js активно использует
scroll события для управления скрытием и отображением шапки
страницы. Без throttle или debounce обработчик будет срабатывать слишком
часто, создавая нагрузку и дерганую анимацию.
Пример интеграции с throttle:
const header = document.querySelector('.header');
const headroom = new Headroom(header, {
tolerance: {
up: 5,
down: 0
},
offset: 100,
onPin: () => console.log('header pinned'),
onUnpin: () => console.log('header unpinned')
});
// Оборачиваем scroll обработчик в throttle для оптимизации
window.addEventListener('scroll', throttle(() => {
headroom.update();
}, 100));
Такой подход гарантирует, что Headroom.js будет обновляться не чаще одного раза в 100 мс, что плавно управляет видимостью шапки и снижает нагрузку на браузер.
Для событий с высокой частотой (scroll, mousemove) предпочтителен throttle.
Для событий, где важно дождаться завершения действия пользователя (поиск, ввод текста) — debounce.
Оптимальные значения интервалов:
Всегда учитывать контекст вызова (this) при обёртке
функций.
Для Headroom.js throttle обеспечивает плавность анимаций и отзывчивость интерфейса без излишних перерисовок.
Throttle и debounce являются фундаментальными инструментами для управления частотой вызова функций в событиях. Их правильное использование повышает производительность страницы, снижает нагрузку на браузер и обеспечивает плавное взаимодействие с пользователем.