• Post last modified:06/04/2020
  • Reading time:9 mins read
  • Post comments:0 Komentarzy

React słynie z tego, iż sam w sobie jest dość szybkim frameworkiem. Zazwyczaj aplikacje tworzone przy jego użyciu działają wystarczająco wydajnie. Jednak czasami małe błędy w implementacji komponentów lub bardzo głębokie zagnieżdżenia mogą wpływać na szybkość działania aplikacji. Dlatego tak bardzo ważne jest wiedzieć jak przebiega monitorowanie wydajności w React.

W tej krótkiej serii artykułów dowiemy się w jaki sposób możemy zwiększyć wydajność aplikacji tworzonych przy użyciu React. Żeby jednak wiedzieć co chcemy zoptymalizować – musimy najpierw sprawdzić jak obecnie zachowują się nasze komponenty.

Highlight Updates

Najczęstszym powodem wolnego działania aplikacji Reactowych są wielokrotne niepotrzebne wywołania metody render w komponentach, które nie muszą być rerenderowane. W większych aplikacjach zazwyczaj ciężko jest wskazać, które komponenty na ekranie są aktualnie renderowane. Jednak z pomocą przychodzą nam tutaj wszystkim dobrze znane React Developer Tools. Bardzo przydatnym narzędziem dostarczonym razem z tą wtyczką jest podświetlanie aktualnie renderujących się komponentów.

Po zaznaczeniu tej opcji, gdy tylko wrócimy do naszej aplikacji z uruchomionymi narzędziami developerskimi i zaczniemy wykonywać na niej jakieś akcje, zauważymy, że komponenty, które aktualnie wykonały metodę render zostaną otoczone kolorową ramką. Kolor tej ramki wskazuje nam jak często rerenderuje się dany komponent. Odcienie niebieskiego oraz zielonego wskazują, iż komponent renderuje się bardzo rzadko. Kolory żółte oraz czerwone mówią nam, iż komponent jest aktualizowany z bardzo dużą częstotliwością. Jeżeli więc po kliknięciu jednego przycisku widzimy wiele czerwonego koloru na ekranie, może to wzbudzić nasze podejrzenia.

Jeżeli chcemy przetestować to narzędzie, możemy otworzyć jedną z wielu przykładowych aplikacji stworzonych w React, do znalezienia np. tutaj lub tutaj. Po odpaleniu narzędzi developerskich Reacta, zaznaczeniu podświetlania aktualizacji , zacząć klikać, wypełniać, scrollować wszystko co tylko znajdziemy na tych stronach.

why-did-you-update

Sama wiedza na temat tego, które komponenty aktualnie wykonują render daje nam już pewne podstawy do tego, żeby zacząć ich optymalizację. Monitorowanie wydajności w React to jednak trochę więce zachodu. Dużo łatwiej byłoby nam jednak znaleźć problem w komponencie, gdybyśmy wiedzieli co tak naprawdę powoduje kolejne wywołania metody render Szczególnie w dość mocno zagnieżdżonych komponentach. Z pomocą przychodzi nam tutaj narzędzie why-did-you-update. W dużym skrócie, biblioteka ta obserwuje nasze komponenty i wyłapuje sytuacje w których zostały one przerenderowane pomimo tego, iż w komponencie nie zmieniły się propsy bądź stan. W celu zaimplementowania biblioteki, wystarczy wywołać poniższy snippet w dowolnym miejscu naszej aplikacji, instalując wcześniej omawianą paczkę: npm i --save-dev why-did-you-update:

import React from 'react'

if (process.env.NODE_ENV !== 'production') { // WAŻNE: NIE UŻYWAĆ W WERSJI PRODUKCYJNEJ !!!
  const {whyDidYouUpdate} = require('why-did-you-update')
  whyDidYouUpdate(React)
}

Teraz wszystkie potencjalnie niepotrzebne wywołania render zostaną umieszczone w konsoli wraz z krótkim komentarzem wyjaśniającym dlaczego dany komponent nie powinien się przerenderować. W idealnej sytuacji, nasza konsola nie powinna zawierać żadnego loga pochodzącego z tej biblioteki.

Performance timeline

Dwa narzędzia które poznaliśmy do tej pory sprawdzą się już całkiem dobrze w wyszukiwaniu potencjalnych problemów. Jednak począwszy od Reacta 15.4 mamy możliwość korzystania z bardzo przydatnego narzędzia znajdującego się w narzędziach developerskich przeglądarki. Jest nim Performance timeline.

Jak sama nazwa wskazuje, mamy tutaj do czynienia z osią czasu na której mamy możliwość dokładnie sprawdzić kiedy nasz komponent został zamontowany, zaktualizowany oraz odmontowany. Dodatkowo mamy możliwość obserwowania co wydarzyło się w konkretnych cyklach życia komponentu.

W celu uruchomienia tego narzędzia musimy wykonać następujące kroki:

  • otworzyć naszą aplikację i dodać parametr react_perf: np: localhost:3000?react_perf,
  • otworzyć narzędzia deevloperskiej (F12 w Chrome), przejść do zakładki Performance i kliknąć przycisk Record (szara kropka w lewym górnym rogu),
  • zatrzymać nagrywanie gdy wykonamy już interesującą nas czynność.

W wyniku tych czynności powinniśmy otrzymać tzw. flamegraph.

Najwięcej wartościowych informacji o naszych komponentach znajdziemy w sekcji User Timing. Natomiast umieszczając kursor na głównej (umiejscowionej najwyżej) osi, będziemy mogli zobaczyć jak wyrenderowana była nasza strona w konkretnym momencie. Warto również na tej osi zwrócić uwagę na czerwone wskaźniki:

redindicator

Wskazują one miejsca w których nasz procesor pracował przez dłuższy czas na nieco zwiększonych obrotach. Zawsze warto sprawdzić co zadziało się w takich miejscach.

Jak odczytywać flamegraph

Jak już wcześniej wspomniałem – powinniśmy rozwinąć sobie sekcję User Timing. Każdy wiersz oznacza komponent który w danym momencie wykonywał jedną ze swoich metod cyklu życia. Czytając od najdłuższego (najwyżej położonego w danej grupie na wykresie) wiersza w dół wchodzimy w kolejne zagnieżdżone w nim komponenty. Czas pracy komponentu jest sumą czasów wykonywania wszystkich zagłebionych komponentów. W ten sposób analizując czasy update’owania zagnieżdżonych komponentów, możemy zidentyfikować komponenty zużywające zdecydowanie więcej czasu niż powinny. Nazwy w nawiasach kwadratowych np. update określają w jakim cyklu życia został on (komponent) zarejestrowany.

Gdy znajdziemy już komponent, który naszym zdaniem powoduje problemy z wydajnością, możemy na niego kliknąć a następnie przejść w dolną część wykresu, posortować listę wg. całkowitego czasu wykonania i sprawdzać plik po pliku, która część naszej aplikacji sprawia najwięcej problemów. bottom

Info

Aby móc poprawnie zidentyfikować pojedyncze pliki, należy pamiętać, aby zawsze używać source-maps przy eksportowaniu plików .js

React Profiler

React Profiler jest najnowszym narzędziem wbudowanym w Reacta, dostępnym od wersji 16.5, które, podobnie jak omówiony już Performance timeline, analizuje zachowanie się komponentów w naszej aplikacji i prezentuje nam flamegraph z informacjami o wszystkich wykonanych renderach. Monitorowanie wydajności w React jest najbardziej efektywne właśnie z jego pomocą.

React Profiler jest dostępny w narzędziach developerskich Reacta. Po uruchomiemiu narzędzi developerskich przeglądarki, przechodzimy do zakładki React, wybieramy podmenu Profiler, klikamy szarą kropkę w celu rozpoczęcia nagrywania. Następnie klikamy wewnątrz naszej aplikacji aby zebrać dane do analizy i kończymy nagrywanie klikając w przycisk Stop.

Po wykonaniu powyższych czynności ukaże nam się flamegraph obrazujący wszystko co wydarzyło się w naszej aplikacji podczas nagrywania.

Info

Warto tutaj wyjaśnić czym w React jest render oraz czym jest commit. Render wywołuje funkcje render() w naszym komponencie i porównuje wynik działania tej funkcji z rezultatem poprzedniego wywołania. Jeżeli rezultaty są takie same – żadne zmiany nie zostają wprowadzone w DOM. Jeżeli jakieś zmiany zostaną wykryte, wykonywana jest faza commitu – w tym momencie React wykonuje manipulacje w DOM. W fazie commitu wywoływane są również metody cyklu życia, np.  componentDidMount() lub componentDidUpdate() w przypadku komponentów klasowych.

Analizując otrzymany wykres powinniśmy zwrócić uwagę na górną belkę – mamy tam możliwość zmiany typu wykresu (o tym za chwilę) oraz widzimy listę commitów (zmiany w DOM), które zostały wprowadzone przez nasze komponenty.

commits

Wysokie słupki o ciepłych barwach (odcienie żółtego i czerwonego) mówią nam, iż taki commit (czyli też render) zajął dużo czasu i potencjalnie może powodować problemy z wydajnością aplikacji. Niskie słupki w zimnych odcieniach obrazują małe commity, kóre nie obciążały mocno aplikacji.

Po klinięciu w określony słupek zmienia on kolor na czarny dzięki czemu widzimy któremu commitowi aktualnie przyglądamy się na flamecharcie. Prawa kolumna Commit information pokazuje nam czas trwania wybranego przez nas commitu.

Zajmijmy się teraz samym flamechartem. Ogólna zasada odczytywania jest taka sama jak w przypadku Performance Timeline. Zaczynając od najwyższego wiersza wchodzimy dalej w zagnieżdżone komponenty. Szerokość wiersza określa jak długo renderował się dany komponent – ponownie ciepłe barwy wskazują długo pracujące komponenty, natomiast zimne wskazują na komponenty szybkie. Komponenty o szarym tle, są to komponety które podczas obserwowanej fazy commitu nie wprowadziły żadnych zmian w DOM. Ich szerokość jest określana na podstawie jednego z poprzednich commitów w którym zostały one wyrenderowane.

Kliknięcie w wybrany komponet pozwala nam na rozwinięcie tego komponentu, dzięki czemu możemy lepiej się przyjrzeć zagnieżdżeniom. A co ważniejsze, mamy możliwość sprawdzić jak wyglądał stan oraz propsy komponentu podczas renderowania. Przeskakując teraz z jednego commitu do drugiego (w górnym prawym oknie), może obserwować jak zmieniał się stan oraz propsy a tym samym dowiedzieć się co spowodowało ponowne renderowanie komponentu.

Podwójne kliknięcie w komponent otwiera nam wykres słupkowy, w którym widzimy ile razy w czasie nagrywania dany komponent wykonywał commit i jak długo on trwał.

Innym rodzajem wykresu, który możemy obserwować wewnątrz tego narzędzia jest wykres o nazwie Ranked. Mamy możliwość zmiany wykresu w lewym górnym rogu okna. W przypadku flamegraph obserwujemy komponenty tak jak są one zagnieżdżone w kodzie. W przypadku wykresu Ranked nasze komponty są ułożone w kolejności odpowiadającej czasom ich renderowania. Ułatwia nam to szybkie wykrycie potencjalnie problematycznych komponentów.

Podsumowanie

Uzbrojeni w garść przydatnych narzędzi możemy teraz dużo łatwiej wyłapać miejsca (komponenty), które mogą spowalniać naszą aplikację. To w jaki sposób możemy zoptymalizować nasz kod, aby przyśpieszyć jego działanie jest tematem na zupełnie nowy wpis – pojawi się on w tym dziale już niedługo. Monitorowanie wydajności w React to dopiero pierwszy krok w jego pełnej optymalizacji.

Kamil Józwik

Frontend developer👨‍💻 Autor kursów na frontschool.pl, małego narzędzia dla programistów - frontbook.dev oraz kolejnych postów na tym blogu. Ulubiony stos technologiczny to React wraz z TypeScript oraz wszystko, co "nowe" w tym pięknym dynamicznym front end-owym świecie 🙂
Subscribe
Powiadom o
guest
0 Comments
Inline Feedbacks
View all comments