Aby debugować JavaScript, otwórz DevTools (F12), przejdź do panelu Sources i kliknij numer linii, w której chcesz zatrzymać program. Po zatrzymaniu sprawdzasz zmienne w panelu Scope i krokujesz kod klawiszami F10 i F11. To samo zrobisz w VS Code, a w Node.js uruchamiając skrypt przez node inspect.Zanim zaczniesz: ten artykuł zakłada, że wiesz, czym jest debugger, breakpoint i krokowanie. Jeśli nie, zacznij od wprowadzenia do debuggera. Tutaj jest praktyka: gdzie kliknąć, co ustawić i dlaczego czasem nic się nie dzieje.
Jak otworzyć debugger w przeglądarce?
W Chrome naciśnij F12 (albo Ctrl+Shift+I, na Macu Cmd+Option+I) i przejdź do panelu Sources. Po lewej widzisz pliki strony, na środku kod wybranego pliku, a po prawej panele debuggera:
| Panel | Do czego służy |
|---|---|
| Breakpoints | lista ustawionych breakpointów i opcje zatrzymywania na wyjątkach |
| Scope | wartości zmiennych w bieżącym miejscu (lokalne, z domknięcia i globalne) |
| Watch | wyrażenia, które sam wpisujesz i które odświeżają się przy każdym kroku |
| Call Stack | łańcuch funkcji, które doprowadziły do zatrzymania |
Nad nimi są przyciski sterowania: wznów (resume, F8), krok dalej (step over, domyślnie F10), krok w głąb (step into, F11) i krok na zewnątrz (step out, Shift+F11). Znaczenie każdego z nich opisuje wprowadzenie do debuggera.
Jak ustawić breakpoint w DevTools?
Najprostszy sposób: w panelu Sources kliknij numer linii. Pojawia się niebieski znacznik, a program zatrzyma się tuż przed wykonaniem tej linii. Odśwież stronę albo wywołaj akcję, która uruchamia ten kod, i debugger zatrzyma się w tym miejscu.
Możesz też wpisać w kodzie instrukcję debugger;. Działa jak breakpoint, ale zapisany w pliku, więc nie zginie po odświeżeniu strony.
Jakie są rodzaje breakpointów i kiedy którego użyć?
DevTools ma kilka rodzajów breakpointów. Dla debugowania na co dzień wystarczy poznać kilka z nich:
| Rodzaj | Jak ustawić | Kiedy użyć |
|---|---|---|
| Linia kodu | klik na numerze linii | gdy wiesz, w którym miejscu kod się psuje |
| Warunkowy (conditional breakpoint) | PPM na numerze linii → Add conditional breakpoint | gdy błąd dotyczy jednej iteracji pętli, np. i === 99 |
| Logpoint | PPM na numerze linii → Add logpoint | gdy chcesz wypisać wartość bez zatrzymywania i bez dopisywania console.log w kodzie |
| Zmiana w DOM | panel Elements → PPM na elemencie → Break on | gdy nie wiesz, który kod zmienia element na stronie |
| XHR/fetch | panel Sources → XHR Breakpoints → dodaj fragment adresu | gdy chcesz zatrzymać się w miejscu wysłania żądania do konkretnego API |
| Zdarzenie | panel Sources → Event Listener Breakpoints | gdy nie wiesz, który kod reaguje na kliknięcie lub inne zdarzenie |
| Wyjątek | panel Sources → Breakpoints → Pause on uncaught exceptions (i opcjonalnie Pause on caught exceptions) | gdy komunikat o błędzie jest, ale nie wiesz, skąd pochodzi |
| Funkcja | wpisz debug(nazwaFunkcji) w konsoli | gdy znasz funkcję, ale nie wiesz, w którym pliku jej szukać |
Dwa z nich zasługują na osobne słowo. Logpoint to najlepsza zamiana dla console.log: nie edytujesz kodu, więc nie zostawisz wydruku w commicie. Breakpoint na wyjątku często oszczędza najwięcej czasu, bo zatrzymuje program w momencie błędu i pokazuje stan, w jakim był.
Jak działa instrukcja debugger i dlaczego czasem jest ignorowana?
Instrukcja debugger; zatrzymuje program tylko wtedy, gdy debugger jest podłączony, czyli gdy w przeglądarce otwarte są DevTools. Przy zamkniętych narzędziach nic nie robi, a skrypt działa dalej. To częsty powód, dla którego ktoś myśli, że „debugger nie działa”.
Są też odwrotne przypadki: debugger; zostawione w kodzie produkcyjnym zatrzyma stronę każdemu, kto otworzy DevTools. Dlatego usuń je przed commitem. Jeśli konkretne debugger; w cudzym skrypcie Ci przeszkadza, kliknij prawym przyciskiem numer tej linii w panelu Sources i wybierz Never pause here.
Jak debugować JavaScript w VS Code?
Zamiast przełączać się do przeglądarki, możesz debugować stronę z poziomu edytora. Są trzy sposoby:
- Debug: Open Link w palecie poleceń (Ctrl+Shift+P, na Macu ⇧⌘P). Wpisujesz adres strony, a VS Code uruchamia przeglądarkę w trybie debugowania.
- JavaScript Debug Terminal. Otwierasz go z poziomu terminala w VS Code i klikasz link do strony.
- Plik
launch.jsonw folderze.vscode, gdy chcesz mieć stałą konfigurację:
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Debuguj stronę w Chrome",
"url": "http://localhost:8000",
"webRoot": "${workspaceFolder}"
}
]
}
Naciśnij F5 i VS Code otworzy stronę. Breakpointy ustawiasz, klikając na lewo od numeru linii w edytorze. Pole webRoot jest opcjonalne i domyślnie wskazuje folder projektu. VS Code używa go do dopasowania plików do mapy źródeł (source map), więc gdy breakpointy się nie zatrzymują, to jedno z pierwszych miejsc do sprawdzenia.
Jak debugować kod w Node.js?
Gdy kod uruchamiasz w terminalu, a nie w przeglądarce, masz dwie drogi:
- Z poziomu terminala:
node inspect plik.jsuruchamia prosty debugger tekstowy. Poleceniecwznawia program,exec wyrażeniepodaje wartość wyrażenia, a.exitkończy sesję. - Z DevTools:
node --inspect-brk plik.jsczeka na podłączenie debuggera. Otwierasz w Chrome adreschrome://inspecti wybierasz uruchomiony skrypt z listy.
W VS Code wystarczy otworzyć JavaScript Debug Terminal i uruchomić node plik.js; edytor sam podłączy debugger i uwzględni breakpointy ustawione w kodzie.
Jak znaleźć błąd asynchroniczny w debuggerze? Przykład z brakującym await
Błędy w kodzie asynchronicznym są trudne, bo komunikat często wskazuje na zupełnie inne miejsce niż przyczyna. Przykład: funkcja pobiera użytkownika i zwraca jego miasto wielkimi literami.
function fetchUser(id) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, name: "Ola", city: "Poznań" }), 50);
});
}
async function getCity(id) {
const user = fetchUser(id);
return user.city.toUpperCase();
}
getCity(1)
.then(console.log)
.catch((error) => console.error(error.message));
Uruchamiasz skrypt i zamiast „POZNAŃ” widzisz:
Cannot read properties of undefined (reading 'toUpperCase')
Komunikat mówi, że user.city jest undefined. Ale w fetchUser miasto przecież jest. Zamiast zgadywać, ustaw breakpoint w linii return user.city.toUpperCase(); i sprawdź, czym jest user (poniżej wynik z Node, który korzysta z tego samego silnika V8 co Chrome):
node inspect city.js
debug> sb(9)
debug> c
break in city.js:9
debug> exec user
Promise
debug> exec typeof user
'object'
debug> exec user.city
undefined
debug> exec user instanceof Promise
true
user jest obietnicą (Promise), a nie obiektem z danymi. Brakuje słowa await przy fetchUser(id), więc funkcja nie czeka na wynik. Obietnica nie ma pola city, stąd undefined. Poprawka to jedno słowo:
const user = await fetchUser(id);
Po niej skrypt wypisuje POZNAŃ. W DevTools ten sam przykład zobaczysz w panelu Scope: przy zmiennej user pojawi się obietnica (Promise) zamiast obiektu z polami. Kroki w DevTools opisuję na podstawie dokumentacji, a przykład uruchomiłem w Node.
Przy krokowaniu przez kod asynchroniczny pamiętaj o jednym: step over na linii z await nie wchodzi w środek wywoływanej funkcji, tylko czeka na jej wynik i zatrzymuje się w następnej linii. Jeśli chcesz zobaczyć, co dzieje się w środku, użyj step into. Więcej o samej asynchroniczności opisują artykuły o testowaniu kodu asynchronicznego i o wykonaniu kodu zależnym od odpowiedzi serwera.
Podobny komunikat (Cannot read properties of undefined) pojawia się też przy odczycie pól obiektu, który nie istnieje. Przykład z formularza opisuje artykuł o walidacji formularza w JavaScript.
Dlaczego breakpoint się nie zatrzymuje? Lista kontrolna
Najczęstsze powody, w kolejności od najprostszych:
- DevTools są zamknięte. Instrukcja
debugger;bez podłączonego debuggera nic nie robi. - Breakpointy są wyłączone. W panelu Sources sprawdź, czy nie wciśnięto przycisku Deactivate breakpoints.
- Kod się nie wykonuje. Linia z breakpointem nie jest uruchamiana: warunek
ifjest fałszywy, zdarzenie nie nastąpiło albo funkcja nigdy nie została wywołana. Ustaw breakpoint wcześniej, na pewno wykonywanej linii, i krokuj dalej. - Breakpoint jest w innym pliku niż ten, który uruchamia przeglądarka. Po zmianie kodu odśwież stronę bez pamięci podręcznej (Ctrl+Shift+R) i upewnij się, że widzisz najnowszą wersję pliku.
- Skrypt jest na liście ignorowanych. DevTools mają listę ignorowanych skryptów (ignore list), które pomijają przy krokowaniu. Panel Call Stack pokaże je po zaznaczeniu opcji Show ignore-listed frames.
- Mapa źródeł (source map) nie pasuje do kodu. Dotyczy projektów z bundlerem, TypeScriptem lub frameworkiem. Breakpoint ustawiony w pliku źródłowym nie trafia w skompilowany kod. W VS Code sprawdź pole
webRootwlaunch.json, a w DevTools, czy plik źródłowy widać pod nazwą z mapy źródeł. - Kod już się wykonał, zanim otworzyłeś DevTools. Dotyczy kodu uruchamianego od razu po załadowaniu strony. Otwórz DevTools, ustaw breakpoint i dopiero wtedy odśwież stronę.
Zacznij od punktów 1–3. Rozwiązują większość przypadków.
Najczęstsze błędy przy debugowaniu JavaScriptu
- Zostawione
debugger;w kodzie. Zatrzymuje stronę każdemu, kto otworzy DevTools. - Breakpoint w skompilowanym pliku zamiast w źródłowym. Zmiany robisz w jednym pliku, a debugger zatrzymuje się w drugim.
- Ufanie temu, co pokazuje
console.log, przy obiektach. Konsola może pokazać obiekt w stanie z chwili rozwinięcia, a nie z chwili wypisania. Dla pewności sprawdzaj wartość w debuggerze, w momencie zatrzymania. - Krokowanie w każdą funkcję biblioteki. Użyj step over, a do własnych funkcji wchodź przez step into.
- Poprawianie bez odtworzenia błędu. Najpierw zapisz scenariusz, który błąd wywołuje, a dopiero potem go naprawiaj.
Podsumowanie
Debugger w JavaScript masz w przeglądarce, w VS Code i w Node. Na początek zapamiętaj trzy rzeczy: kliknij numer linii w panelu Sources, sprawdzaj wartości w panelu Scope i krokuj klawiszami F10 i F11. Gdy kod napisało AI, ten sam proces opisuje artykuł o debugowaniu kodu z AI. Debugger w Pythonie omawia artykuł o debugowaniu w Pythonie.


