9.1 Делегування подій
Робота з подіями в JavaScript може потребувати складного управління для оптимізації продуктивності та покращення архітектури застосунку.
Оптимізація роботи з подіями в JavaScript критично важлива для створення продуктивних веб-застосунків, особливо коли доводиться працювати з великою кількістю елементів. У цьому контексті делегування подій і запобігання зайвих обробників відіграють ключову роль.
Делегування подій — це патерн, при якому обробник подій встановлюється на батьківський елемент, а не на кожен окремий дочірній елемент. Це дозволяє ефективно керувати подіями для великої кількості дочірніх елементів, оскільки обробник викликається лише один раз для батька, а не для кожного елемента.
Приклад без делегування подій:
<!DOCTYPE html>
<html>
<head>
<title>Приклад делегування подій</title>
</head>
<body>
<ul id="list">
<li>Елемент 1</li>
<li>Елемент 2</li>
<li>Елемент 3</li>
</ul>
<script>
const list = document.querySelector('ul');
const items = document.querySelectorAll('#list li');
items.forEach(item => {
item.addEventListener('click', function(event) {
const li = document.createElement('li');
li.innerText = "Новий елемент, подія на якому не спрацює";
list.appendChild(li);
alert(`Ви натиснули на: ${event.target.textContent}`);
});
});
</script>
</body>
</html>
Проблема: якщо список елементів динамічно збільшується, потрібно буде додавати обробники на кожен новий елемент.
Рішення — приклад з делегуванням подій:
<!DOCTYPE html>
<html>
<head>
<title>Приклад делегування подій</title>
</head>
<body>
<ul id="list">
<li>Елемент 1</li>
<li>Елемент 2</li>
<li>Елемент 3</li>
</ul>
<script>
const list = document.getElementById('list');
list.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') {
const li = document.createElement('li');
li.innerText = "Новий елемент, подія на якому спрацює";
list.appendChild(li);
alert(`Ви натиснули на: ${event.target.textContent}`);
}
});
</script>
</body>
</html>
Переваги:
- Обробник додається тільки до батьківського елемента
- Динамічно додані елементи автоматично підтримують обробник подій
9.2 Запобігання зайвим обробникам
Щоб уникнути погіршення продуктивності, важливо мінімізувати кількість обробників подій, особливо якщо вони прикріплені до безлічі елементів або часто викликаються. Декілька підходів до оптимізації:
1. Зменшення кількості обробників: використовуйте делегування подій, щоб скоротити кількість обробників.
2. Використання once в addEventListener: якщо обробник подій повинен спрацювати тільки один раз, використовуйте опцію { once: true } при додаванні обробника.
Приклад:
<!DOCTYPE html>
<html>
<head>
<title>Приклад одноразової події</title>
</head>
<body>
<button id="myButton">Натисни на мене!</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
alert('Ви натиснули на кнопку');
}, { once: true });
</script>
</body>
</html>
3. Debouncing і throttling: ці техніки корисні для оптимізації обробників подій, які часто викликаються, таких як scroll або resize.
9.3 Debouncing
Debouncing об'єднує кілька послідовних викликів функції в один, виконуваний тільки після того, як потік подій припинився.
Приклад:
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));
Спробуйте змінити ширину вікна, щоб побачити результат
Приклад debouncing
У цьому прикладі функція пошуку викликається тільки після того, як користувач перестав вводити текст протягом 300 мілісекунд.
<!DOCTYPE html>
<html>
<head>
<title>Приклад debouncing</title>
</head>
<body>
<div style="min-height: 55px">
<input type="text" id="searchInput" placeholder="Почніть вводити запит...">
<div id="results"></div>
</div>
<script>
const searchInput = document.getElementById('searchInput');
const results = document.getElementById('results');
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
function performSearch(event) {
const query = event.target.value;
results.textContent = 'Пошук: ' + query;
// Імітація запиту до сервера
setTimeout(() => {
results.textContent = 'Ви шукали: ' + query;
}, 500);
}
const debouncedSearch = debounce(performSearch, 300);
searchInput.addEventListener('input', debouncedSearch);
</script>
</body>
</html>
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ