Optymalizacja wydajności interfejsu to jeden z kluczowych elementów tworzenia nowoczesnych stron i aplikacji webowych. Użytkownicy oczekują płynnych animacji, natychmiastowych reakcji na akcje oraz stabilnego działania nawet na słabszych urządzeniach. Gwałtownie rosnąca liczba eventów – przewijanie, ruch kursora, wpisywanie w pola formularzy czy zmiana rozmiaru okna – potrafi jednak szybko przeciążyć przeglądarkę. Właśnie tutaj do gry wchodzą techniki debouncing i throttling, pozwalające precyzyjnie kontrolować częstotliwość wywoływania funkcji i znacząco poprawić wydajność.
Czym są debouncing i throttling w kontekście eventów
Debouncing i throttling to wzorce programistyczne używane głównie przy obsłudze eventów w JavaScript, ale ich idea jest uniwersalna i może być stosowana w innych językach oraz środowiskach. W uproszczeniu obie techniki służą do ograniczania liczby wywołań funkcji, które normalnie byłyby odpalane bardzo często – czasem setki razy na sekundę.
Debouncing opiera się na zasadzie opóźniania wywołania funkcji do momentu, aż nastąpi pewna przerwa w sekwencji eventów. Jeśli w tym czasie pojawi się kolejny event, licznik czasu jest resetowany. Rezultat jest taki, że funkcja uruchamia się dopiero wtedy, gdy użytkownik zakończy serię akcji, na przykład skończy wpisywać tekst w polu wyszukiwarki lub przestanie przewijać stronę.
Throttling z kolei wprowadza stały limit częstotliwości wywołań. Funkcja może zostać uruchomiona maksymalnie raz na określony przedział czasu, na przykład raz na 100 milisekund. Wszystkie eventy, które wystąpią w tym przedziale, są albo ignorowane, albo kolejkowane, w zależności od implementacji. Dzięki temu unika się przeciążenia procesora ogromną liczbą powtarzających się obliczeń.
Obie techniki są szczególnie cenne przy takich eventach jak:
- scroll (przewijanie strony),
- resize (zmiana rozmiaru okna),
- mousemove (ruch kursora),
- keyup / input (wpisywanie tekstu),
- touchmove (gesty na urządzeniach mobilnych).
Bez jakiejkolwiek kontroli tego typu eventy potrafią odpalać funkcje w setkach wywołań na sekundę, co prowadzi do spadku wydajności, zacinania się interfejsu, a czasem nawet do zauważalnych opóźnień w reakcji na inne działania użytkownika. Stosując debouncing lub throttling, programista może precyzyjnie ustalić, jak często dana logika ma się wykonywać, zachowując równowagę między responsywnością a zużyciem zasobów.
Dlaczego niekontrolowane eventy spowalniają strony
Wiele problemów z wydajnością aplikacji webowych nie wynika z pojedynczej złożonej operacji, ale z ogromnej liczby małych obliczeń wykonywanych w krótkim czasie. Na przykład obsługa eventu scroll może zawierać aktualizację pozycji elementów, sprawdzanie widoczności sekcji, wysyłanie danych do narzędzi analitycznych, a nawet generowanie nowych komponentów na stronie. Każde z tych działań może być z pozoru niewinne, lecz łącznie, wykonywane dziesiątki razy na sekundę, tworzy poważne obciążenie.
Przeglądarka musi w takim scenariuszu:
- kilkukrotnie przeliczać układ (reflow) dokumentu,
- ponownie malować (repaint) elementy,
- obsługiwać JavaScript blokujący główny wątek,
- zarządzać pamięcią dla często tworzonych obiektów.
Jeśli eventy są wywoływane bardzo często, kod obsługi może nie zdążyć zakończyć pracy przed nadejściem kolejnego eventu. W efekcie zadania się kumulują, kolejka zdarzeń rośnie, a użytkownik obserwuje zamrożone animacje i opóźnioną reakcję interfejsu. Co gorsza, problem może nasilać się na słabszych urządzeniach, gdzie każdy dodatkowy procent wykorzystania procesora jest wyraźnie odczuwalny.
Dodajmy do tego fakt, że nowoczesne front-endy często korzystają z frameworków, które same z siebie wprowadzają dodatkową warstwę logiki – aktualizacje stanu, wirtualny DOM, wewnętrzne systemy eventów. Każde manualne wywołanie funkcji podczas scrollowania czy ruchu myszy może więc uruchomić łańcuch dalszych operacji: wyrenderowanie komponentu, wywołanie efektów ubocznych, a nawet komunikację z API.
Brak kontroli nad częstotliwością eventów ma też konsekwencje energetyczne. Strona, która stale zużywa wysoki procent mocy obliczeniowej, będzie szybciej rozładowywać baterię urządzenia mobilnego. Dla użytkowników oznacza to krótszy czas pracy na jednym ładowaniu, a dla właścicieli serwisu – potencjalny wzrost współczynnika odrzuceń, ponieważ aplikacja wydaje się ciężka i nieprzyjemna w obsłudze.
Odpowiednio zastosowany debounce i throttle pozwala zmniejszyć gęstość wywołań, bez rezygnowania z istotnych reakcji na zachowanie użytkownika. Zamiast przetwarzać każdy milimetrowy ruch scrolla, można reagować na przykład kilka razy na sekundę i zastosować sprytne kompensacje, aby wizualnie zachować wrażenie płynności. Taki kompromis prowadzi do znacznej poprawy wydajności, nie pogarszając odczuwanej jakości interfejsu.
Debouncing – działanie, zastosowania i przykłady
Debouncing możemy wyobrazić sobie jako mechanizm, który mówi: wykonaj daną funkcję dopiero, gdy użytkownik na chwilę przestanie generować eventy. W praktyce realizuje się to poprzez opóźnienie wywołania docelowej funkcji o określony czas. Jeśli w tym czasie pojawi się kolejny event, stare opóźnienie zostaje anulowane, a rozpoczyna się nowe. Wywołanie następuje dopiero wtedy, gdy minie pełen okres spoczynku.
Typowa implementacja debouncingu w JavaScript sprowadza się do funkcji zwracającej inną funkcję. Wewnętrznie przechowywane jest odwołanie do timera, które jest czyszczone i ustawiane na nowo przy każdym kolejnym wywołaniu wrappera. Taki wzorzec sprawia, że nasz kod przestaje reagować na każde drgnięcie klawiatury czy scrolla, a zaczyna odpowiadać dopiero po zakończeniu serii akcji.
Najbardziej klasyczne zastosowania debouncingu w interfejsach webowych:
- pola wyszukiwania na żywo – zapytanie do serwera jest wysyłane dopiero, gdy użytkownik przestanie pisać na określony czas,
- walidacja formularzy – dana reguła odpala się po chwili spoczynku, a nie przy każdym znaku,
- automatyczne zapisywanie szkiców – zapis następuje po ustaniu aktywności użytkownika,
- dostosowywanie layoutu po resize – zmiany aplikowane są dopiero po zakończeniu zmiany rozmiaru okna.
Wyobraźmy sobie pole wyszukiwania produktów w sklepie internetowym. Bez debouncingu każde wciśnięcie klawisza powodowałoby wysłanie zapytania do API: przy pięciu literach w słowie powstaje pięć zapytań, z których większość staje się natychmiast nieaktualna. Taki nadmiar generuje niepotrzebne obciążenie serwera, marnuje transfer danych i spowalnia reakcję przeglądarki. Zastosowanie debouncingu z opóźnieniem, na przykład 300 ms, sprawia, że zapytanie wyśle się dopiero, gdy użytkownik na moment przerwie pisanie. Sklep pozostaje responsywny, a obciążenie infrastruktury znacząco spada.
Debouncing jest również niezwykle użyteczny w rozbudowanych panelach administracyjnych, gdzie edycja wielu pól jednocześnie mogłaby generować lawinę wewnętrznych aktualizacji. Stosując mechanizm opóźnionego reagowania, twórcy mogą zachować natychmiastową reakcję wizualną przy jednoczesnym ograniczeniu liczby kosztownych operacji, takich jak zapisywanie danych lub przeprowadzanie złożonych walidacji.
Warto zauważyć, że debouncing występuje w dwóch podstawowych wariantach: uruchamianie funkcji na końcu serii eventów (najczęstszy przypadek) oraz uruchamianie na jej początku z opcjonalnym blokowaniem dalszych wywołań przez pewien czas. Ten drugi tryb bywa używany, gdy potrzebujemy natychmiastowej reakcji na pierwszy event, ale nie chcemy, aby kolejne bardzo szybko po sobie wykonywały ten sam kod. Odpowiedni dobór trybu działania ma kluczowe znaczenie dla zachowania interfejsu z punktu widzenia użytkownika.
Throttling – ograniczanie częstotliwości wywołań
Throttling różni się od debouncingu tym, że zamiast czekać na koniec serii eventów, wprowadza stały limit, ile razy w określonym czasie można uruchomić określoną funkcję. Mechanizm możemy porównać do zaworu przepuszczającego tylko pewną liczbę impulsów na sekundę. Niezależnie od tego, jak bardzo użytkownik będzie przesuwał mysz czy przewijał stronę, funkcja nie wykona się częściej niż założony interwał, na przykład co 100 lub 200 milisekund.
W implementacji często używa się zmiennej przechowującej czas ostatniego wywołania. Nowy event sprawdza, czy od tego momentu minęło już wystarczająco dużo czasu. Jeśli tak – funkcja zostaje wykonana i aktualizuje się znacznik czasu. Jeśli nie – event jest ignorowany lub logika jest odkładana do następnego dostępnego okna czasowego. Taki schemat chroni główny wątek przed zalewem redundantnych wywołań.
Typowe zastosowania throttlingu:
- śledzenie pozycji podczas przewijania, na przykład do lazy loadingu lub efektów parallax,
- aktualizacja nagłówka lub nawigacji sticky przy scrollu,
- logowanie zdarzeń analitycznych, aby nie wysyłać setek wpisów na sekundę,
- obsługa ciągłego ruchu myszy w grach i aplikacjach interaktywnych.
Rozważmy przykład zaawansowanej strony z animacjami reagującymi na przewijanie. Bez throttlingu funkcja aktualizująca pozycje i efekty graficzne mogłaby być uruchamiana przy każdym zmianie scrollTop, często kilkadziesiąt razy na sekundę. Gdy w takiej funkcji znajdują się skomplikowane obliczenia czy operacje na DOM, płynność animacji dramatycznie spada. Throttling ustawiony na 60 ms pozwala zachować dobrą responsywność i jednocześnie ogranicza liczbę wywołań do maksymalnie około 16 na sekundę, co jest znacznie bardziej przyjazne dla przeglądarki.
W obszarze analityki throttling pomaga uniknąć zjawiska szumu danych. Na przykład narzędzie śledzące czas spędzony nad konkretną sekcją mogłoby technicznie wysyłać update przy każdym pikselu scrolla. Dzięki limitowaniu częstotliwości raportowania redukujemy nadmiarowe dane, zachowując jednocześnie wystarczającą precyzję do analiz. To z kolei przekłada się na mniejsze obciążenie serwerów analitycznych, niższe koszty i łatwiejszą obróbkę danych.
Z perspektywy projektowania doświadczeń użytkownika ważne jest dobranie odpowiedniego interwału throttlingu. Zbyt krótki nie da odczuwalnych korzyści wydajnościowych, zbyt długi może natomiast sprawić wrażenie, że interfejs reaguje skokowo lub z opóźnieniem. Testowanie na różnych urządzeniach i przeglądarkach jest kluczowe, aby znaleźć punkt równowagi między płynnością a oszczędnością zasobów.
Debounce czy throttle – jak wybrać właściwe podejście
Choć debouncing i throttling mają wspólny cel – ograniczanie liczby wywołań – w praktyce sprawdzają się w odmiennych scenariuszach. Wybór techniki zależy od tego, jakiej reakcji oczekujemy od interfejsu i jak ważne jest uchwycenie każdego pojedynczego ruchu użytkownika.
Debouncing najlepiej sprawdza się wszędzie tam, gdzie działania użytkownika tworzą logiczną całość, a nasza reakcja jest potrzebna dopiero po jej zakończeniu. Klasycznym przykładem jest wpisywanie tekstu. Użytkownik wpisuje całe słowo lub frazę, a logika aplikacji ma sens dopiero po otrzymaniu pełnego ciągu znaków. Gdyby reagować na każdy znak, wyniki wyszukiwania lub komunikaty walidacyjne byłyby stale w ruchu, co mogłoby wprowadzać chaos i obniżać użyteczność interfejsu.
Throttling jest bardziej odpowiedni dla sytuacji, w których istotne jest bieżące śledzenie stanu, ale nie potrzebujemy maksymalnej możliwej szczegółowości. Ruch kursora, pozycja scrolla czy modyfikacje rozmiaru okna bywają potrzebne w sposób ciągły, lecz nieco rzadsze aktualizacje nie wpływają negatywnie na odbiór przez użytkownika. Ważne jest, aby interfejs wydawał się płynny, niekoniecznie idealnie dokładny w każdej milisekundzie.
Przy wyborze między obiema technikami warto zadać sobie kilka pytań:
- czy reakcja powinna nastąpić dopiero po zakończeniu czynności, czy w trakcie jej trwania,
- jak bardzo kosztowna jest operacja wykonywana przy każdym wywołaniu,
- czy pominięcie części eventów może zniekształcić rezultaty działania funkcji,
- jakie są oczekiwania użytkownika dotyczące interaktywności w danym miejscu interfejsu.
W wielu projektach optymalnym podejściem jest połączenie obu wzorców w różnych częściach aplikacji. Na przykład w polu wyszukiwania zastosujemy debouncing, aby zredukować liczbę zapytań do serwera, natomiast do efektów wizualnych przy scrollowaniu użyjemy throttlingu. Bywa też, że jedna funkcja otrzymuje dwie niezależne warstwy kontroli: lekkie odświeżanie widoku pod throttle i cięższe, bardziej szczegółowe obliczenia wyzwalane przez debounce po ustaniu aktywności.
Wpływ debouncingu i throttlingu na UX oraz SEO
Techniki kontroli eventów są zwykle rozpatrywane przez pryzmat wydajności technicznej, ale mają również istotne konsekwencje dla doświadczeń użytkownika i widoczności strony w wyszukiwarkach. Zastosowane nieumiejętnie mogą co prawda spowodować opóźnienia w reakcjach interfejsu, lecz odpowiednio skonfigurowane przynoszą wyraźne korzyści.
Od strony UX poprawnie wdrożony throttling pomaga utrzymać wysoką płynność przewijania i animacji. Użytkownicy postrzegają stronę jako nowocześniejszą i bardziej dopracowaną, gdy przejścia między sekcjami nie szarpią, a przyciągające wzrok efekty nie są okupione spadkami klatek. W przypadku debouncingu korzyścią jest redukcja zbędnych zmian w interfejsie: pole wyboru sugerowanych wyników nie przeskakuje nerwowo przy każdym znaku, a komunikaty o błędach nie migoczą, kiedy użytkownik dopiero stara się poprawnie wprowadzić dane.
Ogólna szybkość i stabilność działania strony ma też znaczenie dla wskaźników jakości ocenianych przez wyszukiwarki, takich jak Core Web Vitals. Nadmiar eventów i niekontrolowane obliczenia w JavaScript mogą wpływać na opóźnienia w interaktywności, co bezpośrednio pogarsza taki parametr jak First Input Delay lub jego nowszy odpowiednik. Ograniczając liczbę wywołań drogich funkcji podczas interakcji, ułatwiamy przeglądarce dostarczanie szybkiej odpowiedzi na pierwsze kliknięcia i gesty użytkownika.
Dobrze przemyślany model obsługi eventów obniża także prawdopodobieństwo błędów wynikających z kolizji wielu jednoczesnych akcji. Mniej chaosu w kolejce zdarzeń przekłada się na mniejszą liczbę trudnych do odtworzenia problemów, które w przeciwnym razie mogłyby przerywać ścieżkę konwersji. To z kolei wpływa zarówno na satysfakcję użytkownika, jak i na wskaźniki biznesowe definiujące sukces serwisu.
Warto przy tym pamiętać, że zarówno debouncing, jak i throttling muszą być testowane z realnymi scenariuszami użytkowania. Zbyt agresywna redukcja wywołań może sprawić, że interfejs będzie reagował nienaturalnie wolno, co może zirytować użytkowników przyzwyczajonych do natychmiastowości. Dokładne dobieranie interwałów czasowych, analizowanie danych z narzędzi analitycznych oraz słuchanie opinii odbiorców pozwala znaleźć optymalną konfigurację, łączącą wydajność z wysoką jakością doświadczeń.
Najlepsze praktyki wdrażania debouncingu i throttlingu
Skuteczne użycie debouncingu i throttlingu wymaga nie tylko znajomości teorii, ale też konsekwentnego stosowania dobrych praktyk w projekcie. Pierwszym krokiem powinno być zidentyfikowanie miejsc, w których eventy generują nadmierne obciążenie. Pomagają w tym narzędzia deweloperskie przeglądarki, profilery wydajności oraz logowanie liczby wywołań funkcji w czasie.
Po wskazaniu krytycznych odcinków kodu warto:
- oddzielić logikę obsługi eventu od logiki biznesowej, aby łatwo owinąć ją w debounce lub throttle,
- unikać zbyt niskich opóźnień – interwał rzędu 50–150 ms jest często rozsądnym punktem wyjścia,
- testować zachowanie na urządzeniach mobilnych, gdzie czułość na opóźnienia jest większa,
- zwrócić uwagę na dostępność – zbyt rzadka aktualizacja może utrudnić korzystanie z czytników ekranu.
Istotne jest także konsekwentne korzystanie ze sprawdzonych implementacji. W wielu projektach front-endowych pojawiają się biblioteki zawierające gotowe funkcje debounce i throttle. Zamiast wprowadzać po raz kolejny własne, nie zawsze dobrze przetestowane wersje, lepiej oprzeć się na takich rozwiązaniach i ewentualnie dopasować parametry do potrzeb konkretnej aplikacji. Ułatwia to też utrzymanie kodu, ponieważ zespół ma jeden standardowy sposób radzenia sobie z tym typem optymalizacji.
Podczas wdrażania tych technik dobrze jest opracować zrozumiałe dla całego zespołu zasady: w jakich sytuacjach preferować debouncing, a w jakich throttling, jakie zakresy opóźnień są zalecane, jak dokumentować powiązane decyzje projektowe. Dzięki temu nowi członkowie zespołu łatwiej odnajdą się w istniejącej bazie kodu, a całość projektu będzie spójna.
Nie można też zapominać o monitorowaniu skutków wprowadzonych optymalizacji. Po dodaniu debounce lub throttle warto porównać dane z rzeczywistego ruchu: czas odpowiedzi interfejsu, stabilność działania, wpływ na współczynnik odrzuceń czy konwersję. Często dopiero analiza realnego zachowania użytkowników pokazuje, czy wybrane ustawienia są trafne, czy też trzeba je skorygować o kilka dziesiątych sekundy, aby osiągnąć lepszy kompromis między szybkością a dokładnością.
Najczęstsze błędy przy używaniu debouncingu i throttlingu
Mimo że debouncing i throttling wydają się prostymi koncepcjami, w praktyce programiści często popełniają błędy, które niwelują potencjalne korzyści. Należy do nich przede wszystkim nadużywanie tych technik – próba owinięcia w nie niemal każdego eventu bez dokładnej analizy potrzeb. W rezultacie interfejs może wydawać się powolny, a użytkownik musi zbyt długo czekać na reakcję aplikacji.
Innym powszechnym problemem jest zbyt duża długość interwału czasu. Dla eventów związanych z przewijaniem czy ruchem myszy zbyt długi throttle może wywoływać wrażenie przeskoków zamiast płynnego przesuwania. Z kolei w przypadku debouncingu ustawienie opóźnienia na przykład na sekundę sprawi, że pole wyszukiwania będzie wydawało się ospałe. Zanim użytkownik zobaczy pierwsze wyniki, może mieć wrażenie, że aplikacja nie zarejestrowała jego wpisu.
Często spotykanym błędem jest też tworzenie nowej funkcji debounce lub throttle przy każdym renderowaniu komponentu, co powoduje utratę wcześniejszego stanu i uniemożliwia prawidłowe działanie mechanizmu. W środowiskach korzystających z komponentów deklaratywnych, jak w popularnych frameworkach, trzeba zwracać szczególną uwagę na to, aby funkcja z opakowaniem była tworzona tylko raz i odpowiednio czyszczona przy odmontowaniu komponentu.
Problematyczne bywa również przeoczenie wpływu debouncingu i throttlingu na testy automatyczne. Testy jednostkowe czy integracyjne korzystające z symulowanych eventów mogą wymagać uwzględnienia opóźnień, co z kolei wymusza stosowanie mechanizmów oczekiwania w testach. Jeżeli programista o tym zapomni, testy zaczną losowo się wywracać lub przechodzić mimo faktycznych problemów z logiką.
Aby uniknąć tych pułapek, warto:
- stosować te techniki tylko tam, gdzie istnieje realny problem wydajnościowy,
- dobierać interwały eksperymentalnie, testując różne wartości z użytkownikami,
- utrzymywać funkcje wrapperów w stabilnym zakresie życia komponentów,
- aktualizować testy o logikę oczekiwania na efekty opóźnionych wywołań.
Podsumowanie korzyści i wpływu na wydajność
Debouncing i throttling są fundamentem świadomego zarządzania eventami w aplikacjach webowych. Dzięki nim można znacznie ograniczyć liczbę wykonywanych operacji, odciążyć główny wątek JavaScript i sprawić, że strona będzie działała stabilniej zarówno na szybkich komputerach, jak i na słabszych urządzeniach mobilnych. W połączeniu z innymi technikami optymalizacji, takimi jak lazy loading, kompresja zasobów czy minimalizacja DOM, stanowią ważny element kompleksowego podejścia do wydajności.
Kluczem do sukcesu jest zrozumienie różnic między obiema technikami i świadome ich stosowanie w zależności od potrzeb interfejsu. Debouncing pomaga tam, gdzie logika powinna zadziałać po zakończeniu serii działań, a throttling – tam, gdzie potrzebne są regularne, lecz nie nadmiernie częste aktualizacje. Odpowiednie połączenie obu podejść pozwala tworzyć interfejsy szybkie, płynne i przyjazne użytkownikowi.
Ostatecznie poprawa wydajności eventów nie jest jedynie kwestią komfortu programisty, ale realnie wpływa na postrzeganą jakość serwisu, jego wyniki biznesowe oraz pozycję w wyszukiwarkach. Zrozumienie i stosowanie debouncingu oraz throttlingu staje się więc koniecznością dla każdego, kto poważnie myśli o rozwijaniu nowoczesnych, skalowalnych i konkurencyjnych aplikacji internetowych.
FAQ
Jakie są główne różnice między debouncingiem a throttlingiem
Debouncing opóźnia wywołanie funkcji do momentu, aż użytkownik przestanie generować eventy przez określony czas. Funkcja wywoływana jest więc po zakończeniu serii akcji. Throttling natomiast ogranicza maksymalną częstotliwość wywołań, pozwalając funkcji wykonać się najwyżej raz na dany interwał, niezależnie od liczby zdarzeń.
Kiedy lepiej zastosować debouncing niż throttling
Debouncing jest korzystny, gdy sens ma tylko końcowy rezultat działań użytkownika, na przykład pełna fraza wpisana w pole wyszukiwania lub zakończenie zmiany rozmiaru okna. W takich sytuacjach reagowanie na każdy drobny krok jest zbędne, a nawet szkodliwe dla wydajności. Debouncing redukuje liczbę wywołań do jednego po serii zmian.
Czy debouncing i throttling wpływają na SEO strony
Pośrednio tak, ponieważ wpływają na wydajność i szybkość interakcji, które uwzględniają wskaźniki jakości strony. Lepsza płynność i krótsze opóźnienia mogą poprawić takie metryki jak czas do pierwszej interakcji i stabilność interfejsu. To z kolei może przełożyć się na lepsze oceny jakości i potencjalnie wyższą pozycję w wynikach wyszukiwania.
Czy można łączyć debouncing i throttling w jednym projekcie
Można, a często nawet warto. Różne części interfejsu mają odmienne wymagania. W polach tekstowych i przy walidacji formularzy lepiej sprawdzi się debouncing, bo logiczny jest wynik po zakończeniu wpisywania. Efekty wizualne przy scrollu czy ruchu myszy korzystają natomiast z throttlingu, który zapewnia stałą, ale kontrolowaną częstotliwość aktualizacji.
Jak dobrać odpowiedni interwał czasu dla tych technik
Interwał warto dobierać eksperymentalnie, obserwując zachowanie aplikacji na różnych urządzeniach. Dobrym punktem wyjścia jest zakres 50–150 ms dla throttlingu i 200–500 ms dla debouncingu. Następnie należy sprawdzić, jak użytkownicy odczuwają responsywność interfejsu oraz jak zmieniają się wskaźniki wydajności, dopasowując wartości według potrzeb.