Throttling и debouncing — это техники управления частотой выполнения функций при обработке событий в JavaScript. Они необходимы для оптимизации производительности интерфейсов, особенно когда события происходят очень часто: скролл, ресайз окна, ввод текста, движение мыши и др.
Throttling ограничивает выполнение функции определённой частотой. Если событие срабатывает слишком часто, функция будет вызвана не чаще, чем заданный интервал времени. Это предотвращает перегрузку браузера при интенсивных событиях.
Debouncing откладывает выполнение функции до момента, пока событие не прекратит срабатывать определённое время. Если событие происходит снова до окончания задержки, таймер сбрасывается. Этот подход полезен, например, для обработки ввода текста, когда требуется выполнить действие только после того, как пользователь закончил ввод.
Простейший пример throttling можно реализовать через функцию
setTimeout:
function throttle(fn, wait) {
let isThrottled = false;
return function (...args) {
if (!isThrottled) {
fn.apply(this, args);
isThrottled = true;
setTimeout(() => {
isThrottled = false;
}, wait);
}
};
}
Применение:
const logScroll = throttle(() => {
console.log(window.scrollY);
}, 200);
window.addEventListener('scroll', logScroll);
В этом примере обработчик скролла будет срабатывать не чаще одного раза каждые 200 миллисекунд. Это снижает нагрузку на браузер при быстром скролле страницы.
Особенности throttling:
Debouncing используется для задержки выполнения функции до тех пор, пока поток событий не остановится.
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
Применение:
const searchInput = document.querySelector('#search');
const fetchResults = debounce(() => {
console.log('Запрос на сервер');
}, 300);
searchInput.addEventListener('input', fetchResults);
В этом случае запрос на сервер будет отправлен только после того, как пользователь перестанет печатать в поле ввода в течение 300 миллисекунд. Это экономит ресурсы и предотвращает излишние сетевые запросы.
Особенности debouncing:
Stickybits — это легковесная библиотека для управления «липкими»
элементами (position: sticky) в браузере, с
кросс-браузерной поддержкой и возможностью добавления полифиллов для
старых версий. Часто при работе с sticky-элементами возникает
необходимость отслеживать скролл страницы или изменение размеров окна.
Без throttling/debouncing обработчики могут вызывать сильное падение
производительности.
Пример с throttling:
import stickybits from 'stickybits';
const stickyElement = document.querySelector('.sticky');
stickybits(stickyElement);
window.addEventListener(
'scroll',
throttle(() => {
console.log('Позиция скролла обновлена для sticky элемента');
}, 100)
);
Здесь позиция скролла отслеживается каждые 100 миллисекунд, что предотвращает перегрузку при интенсивном скролле.
Пример с debouncing:
window.addEventListener(
'resize',
debounce(() => {
console.log('Обновление sticky элементов после изменения размера окна');
stickybits('.sticky', { useStickyClasses: true });
}, 200)
);
При изменении размеров окна обновление sticky элементов будет выполняться только после того, как resize завершится, предотвращая множественные перерасчёты позиции.
Throttling используется для «регулярного» обновления состояния, когда важна непрерывная реакция интерфейса, например:
Debouncing применяется для «финализирующих» действий, когда важна экономия ресурсов и результат нужен один раз после завершения серии событий:
Оптимальная практика с Stickybits: комбинировать throttling для скролла и debouncing для resize, чтобы обеспечить плавность и минимальную нагрузку на браузер.
Stickybits позволяет передавать дополнительные параметры, которые помогают управлять поведением элементов при скролле и resize:
stickybits('.sticky', {
stickyBitStickyOffset: 20, // отступ сверху
useStickyClasses: true, // добавление CSS классов
verticalPosition: 'top', // позиционирование
});
При комбинировании с throttling и debouncing обработчики могут:
.is-sticky только с ограниченной
частотой при скролле.requestAnimationFrame внутри
throttling, если нужно синхронизировать с отрисовкой браузера:function throttleRAF(fn) {
let ticking = false;
return function (...args) {
if (!ticking) {
requestAnimationFrame(() => {
fn.apply(this, args);
ticking = false;
});
ticking = true;
}
};
}
Этот подход обеспечивает плавные обновления без «подёргивания» элементов.
Эти техники являются ключевыми для эффективного использования Stickybits в современных интерфейсах с множеством динамически изменяющихся элементов. Контроль частоты вызовов функций позволяет добиться высокой производительности, даже при сложной верстке и большом количестве sticky блоков.