При работе с динамическими интерфейсами и особенно с библиотекой
Packery часто возникает необходимость контролировать частоту выполнения
функций при срабатывании событий. Классические примеры — события
scroll, resize, mousemove,
которые могут генерироваться сотни раз в секунду. Без контроля это
приводит к замедлению работы страницы и ухудшению пользовательского
опыта. Debounce и throttle — два
основных подхода к решению этой проблемы.
Debounce обеспечивает вызов функции только один раз после того, как событие перестало срабатывать в течение определённого времени. Это особенно полезно для событий, которые генерируются часто, но действия нужно выполнять лишь после завершения их серии.
const grid = document.querySelector('.grid');
const pckry = new Packery(grid, {
itemSelector: '.grid-item',
gutter: 10
});
function layoutItems() {
pckry.layout();
}
// Обёртка debounce
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// Применение debounce при изменении размера окна
window.addEventListener('resize', debounce(layoutItems, 250));
В этом примере layoutItems будет вызываться
только один раз после того, как пользователь закончит изменять
размер окна, даже если событие resize срабатывает
десятки раз в секунду.
Throttle гарантирует, что функция будет вызвана не чаще, чем один раз в заданный интервал времени, независимо от частоты срабатывания события. Подходит для постоянных потоков данных, когда важно получать обновления с определённой регулярностью.
function throttle(fn, limit) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
fn.apply(this, args);
}
};
}
window.addEventListener('scroll', throttle(() => {
console.log('Прокрутка с throttling');
}, 200));
В этом случае функция будет срабатывать максимум один раз каждые 200 миллисекунд, предотвращая чрезмерную нагрузку на браузер при прокрутке страницы.
| Характеристика | Debounce | Throttle |
|---|---|---|
| Вызов функции | После окончания серии событий | Через регулярные интервалы времени |
| Применение | resize, input, автопоиск |
scroll, mousemove, drag & drop |
| Поведение при частых событиях | Игнорирует промежуточные события | Игнорирует события между интервалами, но не пропускает окончание серии |
Ключевой момент: Debounce подходит, когда важно выполнить действие после остановки событий, а Throttle — когда необходимо периодическое обновление состояния при постоянной активности.
Packery активно использует перерасчёт позиций элементов в сетке. При
динамическом изменении размеров контейнера или при добавлении/удалении
элементов частые вызовы layout() могут привести к
торможению интерфейса. Правильное применение debounce и throttle
позволяет:
const addItemBtn = document.querySelector('#add-item');
function addItem() {
const item = document.createElement('div');
item.className = 'grid-item';
grid.appendChild(item);
pckry.appended(item);
pckry.layout();
}
addItemBtn.addEventListener('click', debounce(addItem, 300));
В этом примере, даже если пользователь многократно кликает по кнопке,
функция addItem выполнится лишь один раз каждые 300
миллисекунд.
requestAnimationFrame для максимально плавного обновления
Packery-сетки.Применение debounce и throttle позволяет держать интерфейс отзывчивым, минимизировать лишние перерасчёты и управлять производительностью при работе с Packery и другими динамическими сетками в JavaScript.