Debugowanie kodu

Pisząc kod co chwila będziemy natrafiać na różnego rodzaju błędy. Aby sobie z nimi radzić powinniśmy umieć debugować nasz kod. Poniżej zajmiemy się kilkoma metodami podejścia do takiego zadania.

console

To chyba najprostsza metoda do testowania kodu, którą już trochę omawialiśmy w rozdziale o debuggerze, a i którą non stop używam w listingach.


//wypisanie tekstu
const text = "Moja mała świnka";
console.log(text);

//wypisywanie całego obiektu
console.log(window);

//wypisanie wielu rzeczy po przecinku
const a = 10;
const b = 20;
console.log("a: ", a, "b: ", b);

Wypisując jakieś rzeczy w konsoli wraz z tekstem warto zamiast + używać przecinka. Dzięki temu wypisywany element nie będzie konwertowany na tekst i nie dostaniemy w konsoli głupot.


const obj = { name: "test" }

//zamiast
console.log("Wynik: " + obj); //"Wynik: [object Object]"

//użyj
console.log("Wynik:", obj); //"Wynik:", {name: "test"}

Przy okazji warto tutaj przypomnieć sobie ułatwienie pracy, które pokazałem wam w dziale o debuggerze.

Obiekt console udostępnia nam też kilka innych - równie przydatnych metod, które opisane są na stronie https://developer.mozilla.org/pl/docs/Web/API/Console.

Jeżeli zapomnimy ich listę, wystarczy w konsoli debuggera wpisać słowo console i zbadać wypisany obiekt. W pracy codziennej w większości przypadków wystarczą:


console.log() //klasyk
console.dir() //do bardziej szczegółowego wypisywania obiektów. Szczególnie przydatna przy wypisywaniu elementów DOM
console.table() //wypisuje ładnie sformatowany stan tabeli w danym momencie

Debugowanie za pomocą debuggera

Debugowanie za pomocą console sprawdza się w wielu sytuacjach, i wcale nie trzeba się go wstydzić. Nie zawsze jest jednak optymalną metodą odpluskwiania kodu.

Gdy pojawi się jakiś komunikat, błąd lub informacja, w konsoli po prawej stronie takiego komunikatu będziemy mieli pokazaną linię w kodzie, z której nastąpiło wypisanie danej informacji. Gdy ją klikniemy zostaniemy przeniesieni do zakładki Sources.

debugger console nr linii debugowanie zakładka sources

Aby debugować kod, musimy zatrzymać nasz skrypt w danym miejscu. Możemy to zrobić na kilka sposobów.

Możemy użyć w kodzie słowa kluczowego debugger:


const ob1 = { ... }
const ob2 = { ... }
debugger; //zatrzymujemy wykonywanie kodu

const ob3 = {...ob1, ...ob2};
debugger; //znowu zatrzymujemy - a co!

Kolejnym sposobem, który daje podobne efekty jest użycie tak zwanych breakpointów. Po kliknięciu w numer danej linii, stawiamy w niej breakpoint (niebieski znacznik).

Jeżeli skrypt ponownie się wykona (np. strona zostanie przeładowana, dana funkcja zostanie odpalona itp.), skrypt zostanie zatrzymany w danej linii (dana linijka jeszcze się nie wykona, a kursor stanie na jej początku).

breakpoint

Po zatrzymaniu skryptu (dowolną metodą) najeżdżając na zmienne możemy badać ich aktualny stan:

breakpoint badanie zmiennej

W niektórych przypadkach możemy chcieć zatrzymywać kod na danym breakpoincie tylko w określonym warunku. Powiedzmy, że chcemy zbadać poniższych użytkowników, ale tylko w sytuacji, gdy ich punkty wynoszą poniżej 50:


const users = [
    { name : "Marcin", points : 51 },
    { name : "Weronika", points : 87 },
    { name : "Piotr", points : 65 },
    { name : "Monika", points : 46 },
    { name : "Anna", points : 98 },
]

users.forEach(function(user) {
    console.log(user.name, user.points);
})

Jeżeli teraz postawimy breakpoint w linijce z console.log(), skrypt będzie się zatrzymywać w tej linii przy każdej iteracji naszej pętli. Domyślnie breakpoint taki stawiany jest na początku linii. Oznacza to, że kod zostanie zatrzymany przed wykonaniem danej linii kodu. Gdy postawisz taki breakpoint w większości przypadków będziesz mógł postawić dodatkowe breakpoiny wewnątrz danej linii.

Czasami (szczególnie w przypadku pętli po długich tablicach) może to być mocno problematyczne. Możemy jednak kliknąć na taki niebieski breakpoint prawym przyciskiem i wybrać "Edit breakpoint".

Pojawi się okienko, do którego możemy dodać dodatkowy warunek, który jeżeli będzie spełniony, aktywuje breakpoint.

Breakpoint zmieni kolor na pomarańczowy i od tej pory będzie aktywny tylko w przypadku gdy nasz warunek będzie spełniony.

Aby wznowić działanie skryptów kliknij ikonkę play (znajduje się po prawej stronie zakładki Sources):

ikony breakpointów

lub naciśnij klawisz F8. Skrypt się wznowi i ewentualnie zatrzyma na kolejnym breakpoincie.

Jak widzisz poza ikonką wznawiającą działanie skryptów po prawej stronie mamy też kilka innych.

Wznawia działanie kodu
Jeżeli w danej linii znajduje się wywołanie funkcji, debugger wykona ją, ale nie przeniesie kursora do jej wnętrza, a przeskoczy nim do następnej instrukcji w kodzie. Jeżeli nie ma takiego wywołania, ikonka zachowa się jak przejście do następnego kroku.
Przechodzi kursorem do wnętrza funkcji, lub zachowuje się jak przejście do kolejnego kroku
Wychodzi z danej funkcji i przechodzi do kolejnej linii kodu (czyli poza linię, gdzie dana funkcja została wywołana)
Wyłącza na chwilę breakpointy. Pomocne gdy mamy nastawiane naście takich breakpointów i chcemy na chwilę sprawdzić jak się strona zachowuje bez zatrzymywania
Czy kod ma się zatrzymywać na błędach. Jeżeli włączymy tą opcję, kod będzie zatrzymywał się tuż przed pokazaniem czerwonych błędów w konsoli

Zauważ, że po ustawieniu breakpointów, pojawiają się one nie tylko jako niebieskie punkty na numerycznej linii, ale też jako lista w prawej części zakładki Sources:

breakpoints lista

Sekcja ta ma jeszcze kilka ciekawych rzeczy do zaoferowania, które są bardzo przydatne podczas debugowania.

Watch, CallStack, Scope i XHR

Pierwsza z góry to sekcja Watch.

debugger watch

Służy ona do obserwowania zmiennych. Za pomocą plusa możemy tam podać nazwę zmiennej, którą chcemy nasłuchiwać, a dzięki temu właśnie w tym miejscu będziemy mogli w wygodny sposób sprawdzić jej stan w określonym momencie.

Kolejna sekcja - CallStack - pokazuje kolejność odpalanych funkcji. Funkcje w JavaScript (jak i w innych językach) mogą być odpalane z wnętrza innych funkcji itp. Tutaj możemy podejrzeć właśnie taką kolejność.

Bardzo użyteczna sekcja Scope pozwala nam łatwo sprawdzać zmienne w danym scope. Co to oznacza? Powiedzmy, że postawimy breakpoint wewnątrz danej funkcji. Dzięki tej sekcji w wygodny sposób sprawdzimy, jakie zmienne są używane wewnątrz tej funkcji.

Jeżeli chcesz sprawdzić jej działanie, kliknij w poniższy przycisk. Za pomocą instrukcji debugger postawiłem dla ciebie breakpoint w przykładowej funkcji. Po jego kliknięciu sprawdź gdzie zatrzymał się skrypt i co znajduje się w sekcji Scope.

Kolejną sekcją jest XHR/fetch Breakpoints. Możemy w niej ustawiać breakpointy dla requestów, które będą miały w adresie szukaną frazę.

DOM Breakpoints

Poza breakpointami i instrukcją debugger istnieją też inne sposoby na zatrzymanie skryptu w odpowiednim momencie.

Po pierwsze możemy nakazać przeglądarce zatrzymanie wykonywania skryptów, jeżeli zostanie zmodyfikowany dany element w drzewie DOM. Aby to zrobić wystarczy w zakładce debuggera Elements kliknąć prawym przyciskiem myszy wybrany element, i z menu kontekstowego wybrać opcję Break on.

Menu kontekstowe po kliknięciu na element

Poszczególne opcje oznaczają:

subtree modification zatrzymaj działanie skryptów, gdy zmieni się struktura html danego elementu i jego zawartości (dzieci i zagnieżdżonych elementów)
attribute modifications zatrzymaj skrypty, jeżeli zmieni się zawartość atrybutów danego elementu (np. skrypt zmieni style danego elementu)
node removal - zatrzymaj skrypt jeżeli dany element zostanie usunięty

Sprawdźmy to na przykładzie.
Poniżej mamy 3 przyciski. Pierwszy po kliknięciu zmienia tło (czyli dodaje atrybut style). Drugi zmienia swoją zawartość html, a trzeci po kliknięciu jest usuwany.
Ustaw im odpowiednie "Break on". Zauważ, że po ustawieniu "Break on" dla danego elementu, pojawi się przy nim w zakładce Elements niebieska kropka.

niebieskie kropki przy oznaczonych elementach

Jeżeli takie breakpointy bazujące na zmianach html ustawimy w zakładce Elements, pojawią się one też jako lista z prawej strony w zakładce Source.

debugger zadkładka breakon

Dodatkowo w zakładce Elements gdy badasz dany element po prawej stronie będziesz miał style. Nad prawą kolumną masz zakładki. Style to style, w Computed zobaczysz jak te style widzi przeglądarka. Kolejną zakładką jest Event Listeners, w której możesz podejrzeć listę używanych na danej stronie zdarzeń.

Event Listener

Wracamy do zakładki Source. Poniżej sekcji Breakpoints znajduje się przydatna sekcja Event Listener Breakpoints, która służy do ustawiania breakpointów na dane zdarzenia. Wyobraź sobie, że po kliknięciu, najechaniu kursorem czy dowolnej innej czynności wykonywany jest jakiś kod JavaScript. Skąd mamy jednak wiedzieć, gdzie dana funkcja się znajduje? Wystarczy w sekcji tej znaleźć zdarzenie Click (znajduje się w grupie Mouse) i go zaznaczyć. Od tej pory jeżeli pod dane zdarzenie podpięty jest jakiś kod, nasz kod zostanie w tym miejscu zatrzymany.

breakpoint on click

Sprawdźmy to. Włącz breakpoint dla zdarzeń click i kliknij w poniższy przycisk. Dzięki temu kod zostanie zatrzymany w super tajnej funkcji, której miejsca nikt nigdy nie odkrył (a warto)...

Opcja ta jest mega przydatna na obcych stronach, gdzie zaciekawi nas jakiś efekt. Wystarczy włączyć breakpoint na dane zdarzenie i zacząć badać...

Debugowanie w Visual Studio Code

Jeżeli używamy edytora Visual Studio Code, debugowanie naszego kodu możemy sobie dodatkowo nieco umilić. Istnieje bowiem dodatek zwący się Debugger for Chrome, który umożliwia debugowanie kodu bezpośrednio w edytorze.

Gdy go zainstalujemy, wystarczy przejść w tryb debugowania (klawisz F5 lub wybranie z górnego menu opcji Debug->Start Debuging), a naszym oczom ukaże sie widok z oknami o znaczeniu podobnym do tego, co omawialiśmy powyżej:

debugowanie w vsc

na górze lewej sekcji znajdują się opcje służące do skonfigurowania połączenia oraz jego odpalenia:

debugowanie w VSC - opcje do odpalenia

Po kliknięciu w trybik zostanie otwarty plik z przykładową konfiguracją.


{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome against localhost",
            "url": "http://127.0.0.6:8080",
            "webRoot": "${workspaceFolder}"
        }
    ]
}

Aby móc debugować w edytorze, musimy naszą stronę wcześniej odpalić na jakimś serwerze lokalnym.

Jeżeli pracujemy z jakimś frameworkiem JS - np. Reactem, praktycznie zawsze będziemy mieli odpalony taki serwer (np. react-dev-server).

Jeżeli pracujemy bardziej klasycznie, możemy skorzystać z jednego z wielu serwerów lokalnych. Pomówimy sobie na ten temat w tym rozdziale.

Gdy już odpalimy naszą stronę, musimy adres na jakim została odpalona wpisać w powyższej konfiguracji w parametrze url.

Po podaniu adresu i zapisaniu konfiguracji, możemy odpalić połączenie poprzez zieloną strzałkę. Gdy wszystko pójdzie dobrze, nasza strona powinna się otworzyć w nowym oknie przeglądarki.

Od tej pory możemy zacząć debugować bezpośrednio w edytorze. Oznacza to, że breakpointy możemy stawiać nie tylko w Source, ale też klikając obok numerów linii bezpośrednio w edytorze (pojawią się czerwone kropki), a i boczne okna staną się dla nas pomocne.

debugowanie w VSC
W innych edytorach także istnieje możliwość debugowania kodu w edytorze. Przykładowy film pokazuje jak debugować w programie Webstorm.

Quokka

Inne możliwości ułatwiające pracę z debugowaniem daje nam np. dodatek o nazwie Quokka. Po jego instalacji, będzie nam pokazywał wynik danego równania tuż obok linii.

quokka

Nie sprawdzi się to w każdym rodzaju skryptu, ale dość często może być całkiem wygodnym rozwiązaniem.

Trening czyni mistrza

Jeżeli chcesz sobie potrenować zdobytą wiedzę, zadania znajdują się w repozytorium pod adresem: https://github.com/kartofelek007/zadania

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem.
Aha - i ta strona korzysta z ciasteczek.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.