Как сделать чтобы не было сбоев при большом количестве навешанных обработчиков?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Event Delegation и оптимизация обработчиков
Когда на странице много обработчиков событий, браузер может испытывать задержки и падение производительности. Основная проблема — каждый обработчик занимает память и требует обработки при срабатывании события.
Проблема: прямое навешивание обработчиков
Если навесить обработчик на каждый элемент, это создаст множество слушателей:
// Плохо: каждому элементу свой обработчик
const buttons = document.querySelectorAll("button");
buttons.forEach((btn) => {
btn.addEventListener("click", handleClick); // N обработчиков
});
Решение 1: Event Delegation (делегирование событий)
Используй делегирование — навесь один обработчик на родительский элемент и обработай события через event.target:
// Хорошо: один обработчик для всех элементов
const container = document.getElementById("button-container");
container.addEventListener("click", (event) => {
if (event.target.tagName === "BUTTON") {
handleClick(event);
}
});
Преимущества:
- Одна функция вместо N
- Динамические элементы работают без переподписки
- Меньше памяти и утечек
Решение 2: Debounce и Throttle
Для частых событий (scroll, resize, input) ограничь частоту вызовов:
// Debounce — вызвать ПОСЛЕ прекращения события
function debounce(fn, delay) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
// Throttle — вызвать НЕ ЧАЩЕ чем раз в delay
function throttle(fn, delay) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= delay) {
fn(...args);
lastCall = now;
}
};
}
const handleScroll = throttle(() => {
console.log("Scroll обработан");
}, 100);
window.addEventListener("scroll", handleScroll);
Решение 3: Passive слушатели
Для событий, которые не вызывают preventDefault():
window.addEventListener("scroll", handleScroll, { passive: true });
// passive: true позволяет браузеру оптимизировать прокрутку
Решение 4: Удаление неиспользуемых слушателей
Очищай обработчики при размонтировании компонентов:
useEffect(() => {
const handler = () => { /* ... */ };
element.addEventListener("resize", handler);
return () => element.removeEventListener("resize", handler);
}, []);
React-практики
В React используй встроенную систему событий:
function MyComponent() {
return (
<button onClick={() => console.log("Click")}>
Кнопка
</button>
);
}
React автоматически делегирует события на корневой элемент.
Итого
Для больших списков используй:
- Event delegation — один обработчик на контейнер
- Debounce/Throttle — ограничение частоты для scroll/resize
- Passive listeners — для scroll-событий
- Cleanup — удаление слушателей при размонтировании
Это даёт бесперебойную работу даже с тысячами элементов.