Menu

Konsola i DevTools w JavaScript: debugowanie poza console.log

Metody konsoli i funkcje DevTools, dzięki którym debugowanie JavaScript idzie szybciej niż rozsypywanie console.log po całym kodzie.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Konsola to coś więcej niż log

console.log to pierwsze narzędzie do debugowania, jakie poznaje większość ludzi, i ostatnie, z którego wielu z nich rezygnuje. Działa, ale obiekt console ma kilkanaście innych metod, które sprawiają, że debugowanie jest szybsze i czytelniejsze. A gdy już swobodnie poruszasz się po samych DevTools (breakpointy, stos wywołań, obserwowane wyrażenia), po log sięgasz dużo rzadziej niż kiedyś.

Zacznij od szybkiego przeglądu:

Wszystkie cztery piszą do tej samej konsoli, ale przeglądarki stylują je inaczej: ostrzeżenia dostają żółte tło, błędy czerwone i ikonę, a oba zawierają ślad stosu. Filtry w DevTools pozwalają ukryć albo wyodrębnić każdy poziom, co ma znaczenie, gdy aplikacja produkuje setki komunikatów.

Wypisywanie kilku wartości bez wysiłku

Gdy chcesz zobaczyć kilka zmiennych naraz, nie sklejaj ich w jeden tekst. Przekaż je jako osobne argumenty albo, jeszcze lepiej, owiń w obiekt, żeby każda miała etykietę:

Sztuczka z { user, count } korzysta ze skróconej składni obiektów: nazwa zmiennej staje się kluczem. W konsoli zobaczysz { user: {...}, count: 3 } i możesz rozwinąć user, żeby go obejrzeć. Nie tracisz struktury obiektu, bo nie zamieniasz go na tekst.

console.table dla tablic obiektów

Gdy patrzysz na tablicę obiektów, console.log daje ci zwinięty bałagan. console.table pokazuje ją jako prawdziwą tabelę:

W konsoli przeglądarki pierwsze wywołanie wypisuje wszystkie trzy wiersze z sortowanymi kolumnami. Drugie ogranicza je do name i role. To ogromna wygoda przy wszystkim, co ma kształt danych: odpowiedziach API, wynikach zapytań, sparsowanych plikach CSV.

console.dir vs console.log

Wyglądają podobnie, ale dla elementów DOM zachowują się inaczej:

const el = document.querySelector("button");

console.log(el);   // prints the HTML: <button>Click me</button>
console.dir(el);   // prints the JS object view with all properties

log formatuje elementy jako HTML. dir pokazuje obiekt: każdą właściwość, każdą obsługę zdarzeń, każde odwołanie do obliczonych stylów. Gdy chcesz wiedzieć, jakie metody albo atrybuty ma element, wybierz dir.

Grupowanie powiązanych komunikatów

Długie sesje debugowania zapełniają konsolę szumem. console.group i console.groupEnd zamykają powiązane komunikaty w zwijanym bloku:

Każde wywołanie tworzy nazwaną grupę, którą można zwinąć. Użyj console.groupCollapsed, jeśli grupy mają domyślnie startować zwinięte: przydaje się, gdy chcesz otwierać tylko te, które wyglądają podejrzanie.

Mierzenie czasu za pomocą console.time

Do szybkich pomiarów wydajności trudno o coś lepszego niż console.time i console.timeEnd:

Etykieta w time i timeEnd musi być taka sama. Możesz mieć kilka liczników naraz, każdy z inną etykietą. Do czegoś poważniejszego niż pytanie „czy ta pętla jest wolna?” przejdź do panelu Performance w DevTools, który nagrywa pełną oś czasu i flame chart.

Asercje: wypisz coś tylko wtedy, gdy jest źle

console.assert wypisuje komunikat tylko wtedy, gdy warunek jest fałszywy (falsy). To cichy sposób na zostawienie w kodzie kontroli poprawności bez zaśmiecania konsoli, gdy wszystko jest w porządku:

Dobre dla niezmienników, które powinny zawsze być spełnione. Złe dla rzeczy, które mogą legalnie zawieść: w takich przypadkach rzuć błąd.

Ślad stosu na żądanie

console.trace wypisuje bieżący stos wywołań bez rzucania czegokolwiek. Przydaje się, gdy próbujesz ustalić, kto wywołał funkcję:

Wynik pokazuje inner → outer → (top level). W prawdziwej aplikacji w ten sposób odkrywasz, że debugowana obsługa kliknięcia jest wywoływana z trzech różnych miejsc.

Instrukcja debugger

Najszybszy sposób na zatrzymanie wykonania JavaScript to jedno słowo:

function computeTotal(items) {
    const subtotal = items.reduce((s, i) => s + i.price, 0);
    debugger;
    return subtotal * 1.08;
}

Gdy DevTools są otwarte, debugger; działa jak breakpoint: wykonanie zatrzymuje się na tej linii i dostajesz pełny debugger. Widzisz zmienne w zasięgu i stos wywołań, masz przyciski step over i step into, możesz obliczać wyrażenia na bieżącym stanie. Gdy DevTools są zamknięte, debugger; nic nie robi.

Za pierwszym razem, gdy użyjesz prawdziwego debuggera zamiast console.log, poczujesz się jak z supermocą. Widzisz każdą zmienną w zasięgu, bez decydowania z góry, co wypisać. Możesz przechodzić przez warunki krok po kroku i patrzeć, która gałąź się wykonuje. Naprawa podchwytliwego błędu skraca się z minut do sekund.

Usuń linię debugger przed commitem albo, jeszcze lepiej, ustawiaj breakpointy bezpośrednio w DevTools, klikając numer linii w panelu Sources.

Sztuczki w DevTools, które warto znać

Kilka funkcji, które ludzie przeoczają latami:

  • Breakpointy warunkowe: kliknij prawym przyciskiem numer linii w Sources i ustaw warunek, np. user.id === 42. Breakpoint zadziała tylko wtedy, gdy warunek jest prawdziwy.
  • Logpointy: to samo menu, „Add logpoint”. Wypisują komunikat bez zatrzymywania i bez edytowania kodu.
  • $_ w konsoli: ostatnie obliczone wyrażenie. Uruchom coś, a potem użyj $_, żeby to złapać.
  • $0: element aktualnie zaznaczony w panelu Elements. $0.textContent pozwala zbadać to, co właśnie kliknięto.
  • Zapis jako zmienna: kliknij prawym przyciskiem dowolną wartość w konsoli i wybierz „Store as global variable”. Dostaniesz temp1, temp2 itd. do dalszych eksperymentów.
  • Panel Network → Copy as fetch: zamienia dowolne żądanie w wywołanie fetch(), które wkleisz do konsoli i zmodyfikujesz.

Żadna z nich nie jest niezbędna. Każda oszczędza czas, gdy już wejdzie ci w nawyk.

Sprzątanie przed wdrożeniem

Zapomniane wywołania console.log są nieszkodliwe w trakcie developmentu i hałaśliwe na produkcji. Kilka pomocnych nawyków:

  • Użyj reguły lintera (no-console w ESLint), żeby oznaczać zabłąkane logi, z wyjątkiem warn i error.
  • Owiń rozwlekłe logowanie w warunek: if (process.env.NODE_ENV !== "production") console.log(...).
  • Do szczegółowych komunikatów diagnostycznych używaj console.debug: większość bundlerów i systemów zbierania logów potrafi je odfiltrować.
  • Jeszcze lepiej: użyj małego modułu loggera (albo biblioteki takiej jak debug), żeby włączać i wyłączać kategorie logów bez edytowania kodu.

Logowanie nie jest darmowe. Każde wywołanie serializuje argumenty i zapisuje je do bufora. W gorącej pętli zapomniany log potrafi zauważalnie spowolnić działanie.

Dalej: wyrażenia regularne

Będziesz sporo debugować kod przetwarzający teksty, a duża część takiego kodu używa regexów, najbardziej zwięzłej i najbardziej zagadkowej funkcji języka. Następny rozdział zaczyna się od spokojnego przeglądu wyrażeń regularnych w JavaScript i metod, które z nich korzystają.

Najczęściej zadawane pytania

Czym różni się console.log od console.dir?

console.log wypisuje wartości w domyślnym formacie przeglądarki: elementy DOM pokazuje jako HTML. console.dir zawsze pokazuje widok obiektu JavaScript z jego właściwościami, a tego właśnie potrzebujesz, gdy chcesz zbadać właściwości elementu, a nie jego znaczniki.

Jak debugować JavaScript w Chrome DevTools bez console.log?

Otwórz panel Sources, znajdź swój plik i kliknij numer linii, żeby ustawić breakpoint. Gdy wykonanie dojdzie do tej linii, zatrzyma się, a ty możesz sprawdzać zmienne, przechodzić przez kod krok po kroku i obliczać wyrażenia w konsoli. Możesz też wstawić do kodu instrukcję debugger;, żeby wywołać breakpoint prosto ze źródła.

Jak zmierzyć czas wykonania kodu JavaScript?

Otocz kod wywołaniami console.time('label') i console.timeEnd('label') z tą samą etykietą. Konsola wypisze czas, który upłynął, w milisekundach. Do dokładniejszego profilowania użyj panelu Performance w DevTools i nagraj flame chart wszystkiego, co się wykonało.

Do czego służy console.table?

console.table pokazuje tablice i obiekty w konsoli jako sortowaną tabelę, którą przegląda się dużo łatwiej niż zrzut zagnieżdżonych obiektów. Idealnie sprawdza się przy tablicach obiektów: każdy obiekt staje się wierszem, a jego klucze kolumnami. Drugim argumentem możesz ograniczyć, które kolumny się pojawią.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ