Po prawie miesiącu przerwy wracam z kolejną częścią serii o Chrome DevTools. Tym razem zajmę się sprawą debugowania JavaScriptu. Dla niektórych to może być zaskoczeniem, ale debugowanie aplikacji klasyczną metodą alert(‚dupa’) już dawno przestało być szczytem możliwości 🙂
Chrome pozwala na zatrzymywanie i analizę wykonywania skryptów za pomocą breakpointów. Okazuje się, że breakpointy można ustawiać na kilka różnych sposobów. Dzisiejszy post jest przeglądem tych metod.
Na potrzebę tej części przygotowałem prostą aplikację, która losuje sto liczb i wypisuje je na stronie.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Breakpoints demo</title> | |
<script src="http://code.jquery.com/jquery-latest.js" | |
type="text/javascript"></script> | |
</head> | |
<body> | |
<div id="numbers" /> | |
<script> | |
(function() { | |
function getRandomInt(min, max) { | |
min = Math.ceil(min); | |
max = Math.floor(max); | |
return Math.floor(Math.random() * (max – min + 1)) + min; | |
} | |
for(var i = 0;i < 100;i++) { | |
var x = getRandomInt(0, 100); | |
$('#numbers').append(x).append("<br/>"); | |
if (x === 0) { | |
throw "ZERO!"; | |
} | |
} | |
})(); | |
</script> | |
</body> | |
</html> |
1. Line of code
Najprostsza metoda debugowania – zatrzymuje program zawsze podczas wykonania danej linii. Taki breakpoint można ustawić klikając lewym klawiszem myszy na numer linii.
Ten sam efekt można osiągnąć wpisując debugger w kodzie aplikacji.
2. Breakpoint warunkowy
Załóżmy, że interesuje nas stan aplikacji jedynie w ostatnim obiegu pętli for. Nie musimy dodawać do naszego kodu dodatkowego warunku rodzaju:
if (i == 99) { debugger; }
Zamiast tego można użyć breakpointu warunkowego. W tym celu należy kliknąć prawym przyciskiem myszy na wybraną linie i podać warunek zatrzymania.

3. DOM breakpoints
Kolejnym sposobem na debugowanie aplikacji są DOM breakpoints. Mogą być one przydatne, gdy np. wiele miejsc w kodzie modyfikuje element drzewa strony. Wtedy zamiast stawiać pojedyncze breakpointy w każdym z tych miejsc możemy dodać DOM breakpoint.
Zmodyfikujmy nieco kod naszego dema – zamiast pętli użyjemy dwóch timerów dodających liczby do elementu #numbers.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setInterval(function() { | |
var x = getRandomInt(0, 100); | |
$('#numbers').append(x).append("<br/>"); | |
}, 1000); | |
setInterval(function() { | |
var x = getRandomInt(101, 200); | |
$('#numbers').prepend("<br/>").prepend(x); | |
}, 2000); |
Załóżmy, że interesuje nas, który z timerów dodał konkretną liczbę. Ustawmy w tym celu DOM breakpoint zatrzymujący program, gdy zawartość #numbers ulegnie zmianie (subtree modifications).

Debugger zatrzyma teraz program, gdy jeden z dwóch timerów spróbuje dodać element do #numbers.
Oprócz subtree modifications mamy również do dyspozycji attribute modifications (zatrzymuje program, gdy atrybut elementu ulegnie zmianie) oraz node removal (gdy element zostanie usunięty).
4. XHR breakpoints
Aplikacje JavaScriptowe bardzo często wykonują setki zapytań do zewnętrznych serwisów. Czasem może się to wymknąć spod kontroli i może zdarzyć się, że nasza aplikacja wywołuje nadmierną liczbę zapytań lub pyta zły adres.
Aby zbadać, które miejsce w naszym kodzie wywołuje dane zapytanie możemy zdefiniować XHR breakpoint, który zatrzyma program w momencie, gdy wywołane zostanie zapytanie, którego adres URL zawiera wybraną przez nas frazę.
Zmodyfikujmy nasz skrypt tak, by jeden z timerów pobierał losową liczbę z serwisu random.org za pomocą funkcji fetch (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setInterval(function() { | |
var x = getRandomInt(0, 100); | |
$('#numbers').append(x).append("<br/>"); | |
}, 1000); | |
setInterval(function() { | |
fetch('https://www.random.org/integers/?num=1&min=0&max=100&col=1&base=10&format=plain&rnd=new').then(function(response){ | |
return response.text(); | |
}).then(function(number) { | |
$('#numbers').prepend("<br/>").prepend(number); | |
}); | |
}, 2000); | |
})(); |
Dodajmy teraz XHR breakpoint, który zatrzyma program, gdy wykonane zostanie zapytanie do random.org:

5. Event listener breakpoints
Chrome pozwala na dodawanie breakpointów, które reagują na javascriptowe eventy takie, jak kliknięcie, czy wpisywanie tekstu. Więcej o Event Listenerach można przeczytać poprzedniej części serii.
6. Exception breakpoints
Fajną, choć momentami upierdliwą funkcją są breakpointy wyzwalane w momencie wystąpienia wyjątku. Zmieńmy nasz program tak, by losował tylko 0 lub 1. Gdy wylosowane zostanie 0 rzucony zostanie nieobsłużony wyjątek. Gdy wylosowane zostanie 1, rzucamy i łapiemy wyjątek.
Kliknięcie ikonki pauzy spowoduje zatrzymanie programu, gdy wylosowane zostanie 0. Dodatkowo, jeśl włączymy checkbox Pause on caught exceptions, to program zatrzymany zostanie również wtedy, gdy wylosowana zostanie jedynka.

7. Function breakpoints
Fajną opcją Chrome’a, której wcześniej nie znałem są function breakpoints. Takie breakpointy zatrzymują program, gdy wywołana zostanie dana funkcja. Według dokumentacji DevToolsów aby dodać taki breakpoint należy w kodzie naszej aplikacji dodać linię:
debug(funkcja)
Zmienna funkcja jest identyfikatorem funkcji, którą chcemy śledzić.
Niestety, mi nie udało się odpalić tego breakpointa (ReferenceError) z poziomu kodu i zadziałał dopiero gdy ustawiłem zwykły breakpoint na początku programu i wpisałem w konsoli chrome’a debug(myFunction).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function myFunction() { | |
console.log('my func'); | |
} | |
setInterval(function() { | |
var x = getRandomInt(0, 1); | |
if (x == 0) { | |
myFunction(); | |
} | |
$('#numbers').append(x).append("<br/>"); | |
}, 1000); |

Podsumowanie
Mimo, że najczęściej przy debugowaniu używamy najprostszej metody – zwykłego zatrzymania na danej linijce kodu, to uważam, że warto mieć gdzieś z tyłu głowy pozostałe opisane przeze mnie techniki. Być może pozwolą nam zaoszczędzić kiedyś sporo czasu.
W następnej części zobaczymy, jak za pomocą DevTools analizować wydajność naszej aplikacji.