Поскольку присоединение слишком большого количества обработчиков событий к элементу может привести к снижению производительности, в этой статье мы обсудим, как свести к минимуму присоединение.
Постановка задачи. Мы хотим загружать данные новостей, когда пользователь нажимает на ссылку, и отображать их на странице text-section.
Если к тегам привязки прикреплены обработчики событий, мы можем перехватывать каждый щелчок мыши по ссылке и предотвращать поведение по умолчанию, когда страница не обновляется, после чего следует запрос на получение и заполнение данных при получении.
<html>
<head></head>
<body>
<div>
<span id="news-section">Text area to populate</span>
<ul class="menu-items">
<li>
<a id="arrow-button" href="abc.com?page=1">show more text</a>
</l1>
<li>
<a id="arrow-button" href="abc.com?page=2">show more text</a>
</li>
<li>
<a id="arrow-button" href="abc.com?page=3">show more text</a>
</li>
</ul>
</div>
</body>
</html>
Обычно мы прикрепляли прослушиватели событий к каждому элементу привязки, чтобы перехватывать событие клика.
var anchorElements = document.querySelectorAll('a');
anchorElements.forEach(el => el.addEventListener("click", populateText);
function populateText(e) {
e = e || window.event;
e.preventDefault();
var target = e.target || window.target;
fetchData(target.href)
.then(response => response.text())
.then(renderData);
}
Однако, когда на странице большое количество элементов и к каждому из них прикреплен один или несколько обработчиков событий, это приведет к падению производительности — либо в виде увеличения времени на загрузку большего количества разметки и кода Javascript, либо в виде форма более длительного времени выполнения.
Узел DOM, к которому нам нужно получить доступ и изменить, тем медленнее приложение, особенно потому, что фаза присоединения события обычно происходит во время события onloadили DOMContentReady, что является временем занятости для обработки событий. Присоединение обработчиков событий требует времени обработки, а также памяти для отслеживания каждого обработчика.
Много раз большое количество этих обработчиков событий может вообще не понадобиться. Поскольку пользователь будет щелкать по одной ссылке за раз, а не по всем сотням, мы можем оптимизировать это дальше.
Одна вещь, которую мы знаем наверняка, это то, что событие click после достижения цели будет всплывать в дереве DOM к его последовательным элементам-предкам, пока не достигнет window. Таким образом, мы можем обработать это событие в элементе контейнера, который упаковывает все элементы ссылки, а затем проверить все события щелчка, чтобы увидеть, является ли его целью элемент ссылки. Этот метод известен как делегирование событий.
document.querySelector('.menu-items')
.addEventListener("click", handleClick);
function handleClick(e) {
e = e || window.event;
var target = e.target || e.srcElement;
// prevent default behavior and cancel bubbling
e.preventDefault();
e.stopPropagation();
// exit the function on non-link clicks
if (target.nodeName !== 'A') {
return;
}
fetchData(target.href)
.then(response => response.text())
.then(renderData);
};

Подводя итог использованию делегирования событий, мы:
- Обработка подобных событий на уровне контейнера, а не прикрепление обработчиков к каждому целевому элементу.
- Проверка необходимости обработки события путем проверки его целевого свойства.
- Остановка дальнейшего всплытия события (необязательно).