CodeGym /Kursy /Frontend SELF PL /Optymalizacja zdarzeń

Optymalizacja zdarzeń

Frontend SELF PL
Poziom 42 , Lekcja 3
Dostępny

9.1 Delegowanie zdarzeń

Praca ze zdarzeniami w JavaScript może wymagać skomplikowanego zarządzania, aby zoptymalizować wydajność i poprawić architekturę aplikacji.

Optymalizacja pracy ze zdarzeniami w JavaScript jest kluczowa dla tworzenia wydajnych aplikacji webowych, szczególnie gdy trzeba pracować z dużą ilością elementów. W tym kontekście delegowanie zdarzeń i unikanie zbędnych handlerów odgrywają kluczową rolę.

Delegowanie zdarzeń — to wzorzec, przy którym handler zdarzenia jest ustawiany na element nadrzędny, a nie na każdy pojedynczy element potomny. Pozwala to efektywnie zarządzać zdarzeniami dla dużej liczby elementów potomnych, ponieważ handler wywoływany jest tylko raz dla rodzica, a nie dla każdego elementu.

Przykład bez delegowania zdarzeń:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład delegowania zdarzeń</title>
        </head>
        <body>
          <ul id="list">
            <li>Element 1</li>
            <li>Element 2</li>
            <li>Element 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 = "Nowy element, zdarzenie na którym nie zadziała";
                list.appendChild(li);
                alert(`Kliknąłeś na: ${event.target.textContent}`);
              });
            });
          </script>
        </body>
      </html>
    
  

Problem: jeśli lista elementów dynamicznie się powiększa, trzeba będzie dodawać handler na każdy nowy element.

Rozwiązanie — przykład z delegowaniem zdarzeń:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład delegowania zdarzeń</title>
        </head>
        <body>
          <ul id="list">
            <li>Element 1</li>
            <li>Element 2</li>
            <li>Element 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 = "Nowy element, zdarzenie na którym zadziała";
                list.appendChild(li);
                alert(`Kliknąłeś na: ${event.target.textContent}`);
              }
            });
          </script>
        </body>
      </html>
    
  

Zalety:

  • Handler dodawany jest tylko do elementu nadrzędnego
  • Dynamically added elements will automatically support the event handler

9.2 Unikanie zbędnych handlerów

Aby uniknąć pogorszenia wydajności, ważne jest, aby zminimalizować liczbę handlerów zdarzeń, zwłaszcza jeśli są one przypisywane do wielu elementów lub często wywoływane. Kilka podejść do optymalizacji:

1. Zmniejszenie liczby handlerów: używaj delegowania zdarzeń, aby zredukować liczbę handlerów.

2. Używanie once w addEventListener: jeśli handler zdarzeń ma się wywołać tylko raz, użyj opcji { once: true } przy dodawaniu handlera.

Przykład:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład jednorazowego zdarzenia</title>
        </head>
        <body>
          <button id="myButton">Kliknij na mnie!</button>
          <script>
            const button = document.getElementById('myButton');
            button.addEventListener('click', function(event) {
              alert('Kliknąłeś na przycisk');
            }, { once: true });
          </script>
        </body>
      </html>
    
  

3. Debouncing i throttling: te techniki są przydatne do optymalizacji handlerów zdarzeń, które często są wywoływane, takich jak scroll lub resize.

9.3 Debouncing

Debouncing łączy kilka kolejnych wywołań funkcji w jedno, wykonywane tylko po tym, jak przepływ zdarzeń ustanie.

Przykład:

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));
    
  

Spróbuj zmienić szerokość widgetu, aby zobaczyć wynik

Przykład debouncowania

W tym przykładzie funkcja wyszukiwania jest wywoływana dopiero po tym, jak użytkownik przestanie wprowadzać tekst przez 300 milisekund.

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład debouncowania</title>
        </head>
        <body>
          <div style="min-height: 55px">
            <input type="text" id="searchInput" placeholder="Zacznij wpisywać zapytanie...">
            <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 = 'Szukaj: ' + query;
              // Symulacja zapytania do serwera
              setTimeout(() => {
                results.textContent = 'Szukano: ' + query;
              }, 500);
            }

            const debouncedSearch = debounce(performSearch, 300);

            searchInput.addEventListener('input', debouncedSearch);
          </script>
        </body>
      </html>
    
  
HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład debouncowania</title>
        </head>
        <body>
          <input type="text" id="searchInput" placeholder="Zacznij wpisywać zapytanie...">
          <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;
              // Symulacja zapytania do serwera
              setTimeout(() => {
                results.textContent = 'Szukano: ' + query;
              }, 500);
            }

            const debouncedSearch = debounce(performSearch, 300);

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

9.4 Throttling

Trolling Throttling gwarantuje, że funkcja będzie wywoływana nie częściej niż raz w określonym czasie.

Przykład:

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));
    
  

Kolejny przykład throttlingu

W tym przykładzie handler scrollowania jest wywoływany nie częściej niż co 200 milisekund, co pomaga zapobiec przeciążeniu przeglądarki przy częstych zdarzeniach scrollowania.

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>Przykład throttlingu</title>
        </head>
        <body>
          <div id="scrollContainer" style="height: 200px; overflow-y: scroll;">
            <div style="height: 1000px;"></div>
          </div>
          <div id="status">Zacznij przewijać, aby zobaczyć efekt</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 = 'Przewijanie... ' + new Date().toLocaleTimeString();
            }

            const throttledScroll = throttle(handleScroll, 200);

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

9.5 Optymalizacja zdarzeń za pomocą pasywnych słuchaczy

Pasywne słuchacze zdarzeń (passive event listeners) są używane do poprawy wydajności, szczególnie przy obsłudze zdarzeń scrollowania (scroll). Kiedy handler zdarzenia jest ustawiony jako pasywny, oznacza to, że nie będzie wywoływał preventDefault(), co pozwala przeglądarce zoptymalizować wydajność.

Przykład:

JavaScript
    
      window.addEventListener('scroll', function(event) {
        console.log('Scrolling');
      }, { passive: true });
    
  
1
Zadanie
Frontend SELF PL, poziom 42, lekcja 3
Niedostępne
Debouncing input
Debouncing input
1
Zadanie
Frontend SELF PL, poziom 42, lekcja 3
Niedostępne
Throttling przewijania
Throttling przewijania
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION