JavaRush /Курсы /Модуль 1: Web Core /Оптимизация событий

Оптимизация событий

Модуль 1: Web Core
21 уровень , 8 лекция
Открыта

9.1 Делегирование событий

Работа с событиями в JavaScript может потребовать сложного управления для оптимизации производительности и улучшения архитектуры приложения.

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

Делегирование событий — это паттерн, при котором обработчик события устанавливается на родительский элемент, а не на каждый отдельный дочерний элемент. Это позволяет эффективно управлять событиями для большого числа дочерних элементов, так как обработчик вызывается только один раз для родителя, а не для каждого элемента.

Пример без делегирования событий:

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.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>
    
  

Проблема: если список элементов динамически увеличивается, нужно будет добавлять обработчики на каждый новый элемент.

Решение — пример с делегированием событий:

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 } при добавлении обработчика.

Пример:

HTML
    
      <!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. Дебаунсинг и троттлинг: эти техники полезны для оптимизации обработчиков событий, которые часто вызываются, таких как scroll или resize.

9.3 Дебаунсинг

Дебаунсинг объединяет несколько последовательных вызовов функции в один, выполняемый только после того, как поток событий прекратился.

Пример:

JavaScript
    
      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('Window resized');
      }, 300));
    
  

Попробуйте изменить ширину виджета, чтобы увидеть результат

Пример дебаунсинга

В этом примере функция поиска вызывается только после того, как пользователь перестал вводить текст в течение 300 миллисекунд.

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Пример дебаунсинга</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>
    
  
HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Пример дебаунсинга</title>
        </head>
        <body>
          <input type="text" id="searchInput" placeholder="Начните вводить запрос...">
          <div id="results"></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 = 'Searching for: ' + query;
              // Имитация запроса к серверу
              setTimeout(() => {
                results.textContent = 'Вы искали: ' + query;
              }, 500);
            }

            const debouncedSearch = debounce(performSearch, 300);

            searchInput.addEventListener('input', debouncedSearch);
          </script>
        </body>
      </html>
    
  

9.4 Троттлинг

Троллинг Троттлинг гарантирует, что функция будет вызвана не чаще чем один раз за указанный промежуток времени.

Пример:

JavaScript
    
      function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
          const context = this;
          if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
          }
        };
      }

      window.addEventListener('scroll', throttle(() => {
        console.log('Window scrolled');
      }, 300));
    
  

Еще один пример троттлинга

В этом примере обработчик прокрутки вызывается не чаще, чем каждые 200 миллисекунд, что помогает предотвратить перегрузку браузера при частых событиях прокрутки.

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Пример троттлинга</title>
        </head>
        <body>
          <div id="scrollContainer" style="height: 200px; overflow-y: scroll;">
            <div style="height: 1000px;"></div>
          </div>
          <div id="status">Начните скролить, чтобы увидеть эффект</div>

          <script>
            const scrollContainer = document.getElementById('scrollContainer');
            const status = document.getElementById('status');

            function throttle(func, limit) {
              let lastFunc;
              let lastRan;
              return function(...args) {
                const context = this;
                if (!lastRan) {
                  func.apply(context, args);
                  lastRan = Date.now();
                } else {
                  clearTimeout(lastFunc);
                  lastFunc = setTimeout(() => {
                    if ((Date.now() - lastRan) >= limit) {
                      func.apply(context, args);
                      lastRan = Date.now();
                    }
                  }, limit - (Date.now() - lastRan));
                }
              };
            }

            function handleScroll(event) {
              status.textContent = 'Скроллинг... ' + new Date().toLocaleTimeString();
            }

            const throttledScroll = throttle(handleScroll, 200);

            scrollContainer.addEventListener('scroll', throttledScroll);
          </script>
        </body>
      </html>
    
  

9.5 Оптимизация событий с помощью пассивных слушателей

Пассивные слушатели событий (passive event listeners) используются для улучшения производительности, особенно при обработке событий прокрутки (scroll). Когда обработчик события установлен как пассивный, это означает, что он не будет вызывать preventDefault(), что позволяет браузеру оптимизировать производительность.

Пример:

JavaScript
    
      window.addEventListener('scroll', function(event) {
        console.log('Scrolling');
      }, { passive: true });
    
  
1
Задача
Модуль 1: Web Core, 21 уровень, 8 лекция
Недоступна
Дебаунсинг ввода
Дебаунсинг ввода
1
Задача
Модуль 1: Web Core, 21 уровень, 8 лекция
Недоступна
Троттлинг прокрутки
Троттлинг прокрутки
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ