В веб-разработке часто возникает необходимость контролировать частоту
вызова функций, особенно при работе с динамическим контентом и событиями
пользовательского интерфейса, такими как scroll,
resize, mousemove или input.
Библиотека Muuri, предназначенная для управления сетками и анимациями
элементов, активно использует события DOM для пересчёта положения
элементов, поэтому умение применять throttling и
debouncing критически важно для производительности и
плавности интерфейса.
Throttling ограничивает частоту выполнения функции, гарантируя, что она будет вызываться не чаще, чем через определённый промежуток времени. Это полезно, когда события происходят часто, но обработка каждого события не требуется.
Пример базового throttling для Muuri:
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// Создание сетки Muuri
const grid = new Muuri('.grid', {
dragEnabled: true
});
// Пересчёт расположения элементов при изменении размеров окна
window.addEventListener('resize', throttle(() => grid.refreshItems().layout(), 200));
В данном примере функция grid.refreshItems().layout()
будет выполняться не чаще одного раза каждые 200 миллисекунд, независимо
от того, сколько раз срабатывает событие resize.
Ключевые моменты применения throttling:
Debouncing откладывает выполнение функции до тех пор, пока не прекратятся события в течение заданного интервала времени. Это эффективно, когда требуется выполнить действие только после окончания серии событий.
Пример debouncing для Muuri:
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
}
}
// Обновление сетки после ввода текста в фильтр
const filterInput = document.querySelector('#filter');
filterInput.addEventListener('input', debounce(() => {
const query = filterInput.value.toLowerCase();
grid.filter(item => item.getElement().textContent.toLowerCase().includes(query));
}, 300));
В этом случае фильтрация элементов произойдёт только через 300 миллисекунд после того, как пользователь перестанет вводить текст. Если пользователь продолжает печатать, функция откладывается, предотвращая лишние вычисления.
Основные принципы debouncing:
| Характеристика | Throttle | Debounce |
|---|---|---|
| Цель | Ограничить частоту вызова функции | Выполнить функцию только после окончания событий |
| Когда выполняется | Регулярно через фиксированный интервал | Один раз после того, как события прекратились |
| Применение в Muuri | События scroll, resize, drag-and-drop |
Фильтры, поиск, динамическая сортировка |
Перетаскивание элементов (drag)
Drag-and-drop операции генерируют множество событий. Throttling
позволяет обновлять позиции сетки с интервалом, избегая постоянных
перерасчётов.
grid.on('dragMove', throttle((item) => {
grid.refreshItems().layout();
}, 50));Фильтрация и поиск Debouncing предотвращает многократные вызовы фильтрации при вводе текста пользователем.
Изменение размеров окна (resize)
Для пересчёта сетки после изменения окна оптимально использовать
throttling, чтобы layout выполнялся с ограниченной частотой.
Анимации и эффекты при скролле Throttle позволяет регулировать обновление визуальных эффектов Muuri при прокрутке, сохраняя плавность и стабильность FPS.
Иногда целесообразно комбинировать оба подхода: использовать throttling для регулярного обновления состояния сетки и debouncing для финального корректного расположения элементов после серии быстрых событий.
const updateGridThrottled = throttle(() => grid.refreshItems().layout(), 100);
const finalizeGridDebounced = debounce(() => grid.refreshItems().layout(true), 300);
window.addEventListener('resize', () => {
updateGridThrottled();
finalizeGridDebounced();
});
Такой подход обеспечивает плавное и отзывчивое взаимодействие, минимизируя нагрузку на браузер и предотвращая дрожание элементов.
Эти приёмы обеспечивают стабильную и предсказуемую работу Muuri в динамических интерфейсах, особенно при больших сетках и интенсивном взаимодействии с пользователем.