Breakpoint adalah tanda di satu baris kode yang bikin browser berhenti tepat sebelum baris itu jalan. Selama berhenti (paused), kamu bisa membaca isi semua variabel saat itu, lalu maju baris demi baris (stepping). Bayangin nonton ulang gol lewat VAR: videonya di-pause tepat sebelum kejadian, kamu lihat posisi semua pemain, lalu maju satu frame demi satu frame sampai ketemu momen pelanggarannya. console.log cuma memberi satu foto; breakpoint memberi tombol pause dan maju.
🧪 Tebakan cepat: kode berhenti di baris
const harga = hitungDiskon(item.harga, item.diskon);, lalu kamu tekan Step over. DevTools berhenti di dalamhitungDiskon, atau di baris berikutnya? Tebak dulu, jawabannya ada di bagian "Melangkah: step over, step into, step out".
Program yang kita debug
Keranjang ini harusnya bertotal 105.000: Buku 50.000 diskon 10% dikali 2 (90.000), ditambah Pensil 5.000 dikali 3 (15.000). Tapi console mencetak NaN (Not a Number), dan gak ada error merah sama sekali.
function hitungDiskon(harga, persen) {
const potongan = harga * persen / 100;
return harga - potongan;
}
function hitungTotal(keranjang) {
let total = 0;
for (const item of keranjang) {
const harga = hitungDiskon(item.harga, item.diskon);
total += harga * item.qty;
}
return total;
}
const keranjang = [
{ nama: "Buku", harga: 50000, qty: 2, diskon: 10 },
{ nama: "Pensil", harga: 5000, qty: 3 },
];
console.log(hitungTotal(keranjang)); // NaN
Nomor baris di pelajaran ini mengikuti kode di atas: baris 2 const potongan, baris 9 const harga = hitungDiskon(...), baris 10 total += ....
Pasang breakpoint dan berhenti
- Buka DevTools (F12, atau Ctrl+Shift+I; di Mac Cmd+Option+I), lalu pilih panel Sources.
- Di daftar file sebelah kiri, buka
app.js. - Klik nomor baris 9. Muncul penanda biru: itu breakpoint-nya.
- Jalankan lagi kodenya (reload halaman, atau klik tombol yang memicunya).
Halaman berhenti, baris 9 disorot, dan sidebar kanan menulis Paused on breakpoint. Ingat: baris yang disorot belum jalan. harga baru terisi setelah kamu maju satu langkah.
Cara kedua: tulis debugger; di kode. Browser berhenti di sana kalau DevTools sedang terbuka, dan mengabaikannya kalau tertutup.
Membaca Scope dan Call Stack
Waktu paused, sidebar kanan menampilkan dua bagian yang paling sering dipakai. Ini isinya saat program berhenti di dalam hitungDiskon untuk Pensil:
Scope
Local
harga: 5000
persen: undefined
potongan: <value unavailable>
this: Window
Script
keranjang: (2) [{…}, {…}]
Global Window
Call Stack
hitungDiskon app.js:2
hitungTotal app.js:9
(anonymous) app.js:19
- Local: parameter dan variabel fungsi yang sedang jalan.
persen: undefineddi sini adalah biangNaN-nya: Pensil gak punyadiskon. - Block: variabel
let/constdi dalam kurung kurawal, misalnyaitemdanhargadi badan loop. Muncul kalau kamu berhenti di dalam blok itu. - Script berisi
const/letdi level paling atas file, Global berisiwindow. <value unavailable>artinya baris deklarasinya belum jalan, jadi variabelnya belum punya nilai.- Call Stack adalah urutan fungsi yang sedang berjalan, dibaca dari atas:
hitungDiskon(kamu di sini) dipanggilhitungTotaldi baris 9, yang dipanggil kode level atas di baris 19.(anonymous)adalah kode di luar fungsi. Klik satu baris Call Stack untuk melihat Scope milik level itu.
Mau memantau satu ekspresi terus-terusan? Tambahkan di bagian Watch, misalnya item.diskon. Nilainya diperbarui tiap kali kode berhenti.
Melangkah: step over, step into, step out
| Tombol | Windows/Linux | Mac | Yang terjadi |
|---|---|---|---|
| Resume | F8 | Cmd+\ | lanjut sampai breakpoint berikutnya, atau sampai selesai |
| Step over | F10 | Cmd+' | jalankan baris ini sampai selesai, termasuk fungsi yang dipanggilnya, lalu berhenti di baris berikutnya |
| Step into | F11 | Cmd+; | kalau baris ini memanggil fungsi, masuk dan berhenti di baris pertama fungsi itu |
| Step out | Shift+F11 | Cmd+Shift+; | jalankan sisa fungsi ini, lalu berhenti lagi di fungsi pemanggilnya |
Ini jejak sebenarnya kalau kamu mulai dari breakpoint di baris 9:
| Langkah | Tombol | Berhenti di | Yang penting di Scope |
|---|---|---|---|
| 1 | Resume | baris 9, item Buku | total: 0 |
| 2 | Step into | baris 2, di hitungDiskon |
harga: 50000, persen: 10 |
| 3 | Step out | baris 10, kembali di hitungTotal |
harga: 45000 |
| 4 | Step over | baris 8, ambil item berikutnya | total: 90000 |
| 5 | Step over | baris 9, item Pensil | item: {nama: 'Pensil', harga: 5000, qty: 3} |
| 6 | Step into | baris 2, di hitungDiskon |
harga: 5000, persen: undefined |
Dari baris 9, Step over menjalankan hitungDiskon sampai selesai tanpa masuk, lalu berhenti di baris 10. Itu jawaban tebakannya. Step into dari baris yang sama berhenti di baris 2. Satu detail: di baris return, DevTools berhenti dua kali, sebelum nilainya dihitung lalu sesudahnya, dengan Return value muncul di Local.
Conditional breakpoint dan logpoint
Breakpoint biasa di baris 10 berhenti di tiap putaran loop. Dengan dua item itu masih oke, dengan 1.000 item kamu menekan Resume 1.000 kali.
- Conditional breakpoint: klik kanan nomor baris 10, pilih Add conditional breakpoint…, ketik
Number.isNaN(harga), tekan Enter. Penandanya jadi oranye. DevTools mengecek kondisinya tiap kali sampai di baris itu dan cuma berhenti kalau hasilnyatrue. Di program kita: berhenti sekali, di putaran Pensil. - Logpoint: klik kanan nomor baris, pilih Add logpoint…, ketik
"harga", harga, "total", total. Penandanya jadi merah muda. Kode gak berhenti, tapi tiap kali baris itu dicapai, nilainya dicetak ke Console:
harga 45000 total 0
harga NaN total 90000
NaN
Logpoint mencatat nilai sebelum baris 10 jalan, jadi total masih nilai lama. Breakpoint dan logpoint disimpan DevTools, bukan di file kamu: tetap ada setelah reload, dan gak ikut ke commit. Makanya logpoint pas untuk kode yang gak boleh atau gak bisa kamu edit, misalnya library atau build production.
Latihan: conditional breakpoint versi mini
Di latihan, kamu bikin runtime kecil yang meniru cara DevTools memutuskan berhenti. Breakpoint disimpan sebagai pasangan baris dan kondisi. Tiap langkah step(line, state) dicatat sebagai hit hanya kalau ada breakpoint di baris itu dan kondisinya true.
function makeBreakpointRunner() {
const breakpoints = new Map(); // baris -> kondisi
const hits = [];
return {
addBreakpoint(line, condition) {
breakpoints.set(line, condition);
},
step(line, state) {
const condition = breakpoints.get(line);
if (condition && condition(state)) hits.push({ line, state });
},
getHits() {
return hits;
},
};
}
traceStepThrough di kode awal memasang breakpoint di baris 10 dengan s.count > 5 dan di baris 20 dengan !!s.error, lalu menjalankan enam langkah:
| Langkah | Breakpoint di baris itu | Kondisi | Hasil |
|---|---|---|---|
step(10, { count: 3 }) |
ada | 3 > 5 false |
lewat |
step(10, { count: 7 }) |
ada | 7 > 5 true |
hit ke-1 |
step(15, { count: 7 }) |
gak ada | lewat | |
step(20, { error: null }) |
ada | !!null false |
lewat |
step(20, { error: 'oom' }) |
ada | !!'oom' true |
hit ke-2 |
step(10, { count: 9 }) |
ada | 9 > 5 true |
hit ke-3 |
Jadi console mencetak 3 (jumlah hit), 10 dan 7 (baris dan count hit pertama), 20 dan oom (baris dan error hit kedua), lalu 9 (count hit ketiga).
🎯 Breakpoint jenis lain
- DOM breakpoint: di panel Elements, klik kanan elemen, pilih Break on, lalu subtree modifications (anaknya berubah), attribute modifications (class atau style berubah), atau node removal (elemennya dihapus). Kode berhenti di baris JavaScript yang mengubahnya.
- XHR/fetch Breakpoints di sidebar Sources: klik
+, isi potongan URL seperti/api/orders. Kode berhenti tepat sebelum request itu dikirim, jadi Call Stack menunjukkan siapa yang memanggilnya. - Event Listener Breakpoints: centang misalnya Mouse >
click. Klik apa pun di halaman, dan kode berhenti di handler-nya, walaupun kamu belum tahu handler itu ada di file mana. - Never pause here: klik kanan nomor baris di kode yang bukan targetmu, supaya DevTools gak pernah berhenti di sana.
⚠️ Jebakan yang sering ketemu
- Mengira baris yang disorot sudah jalan. Belum. Variabel di baris itu baru terisi setelah satu langkah.
- Mengira Step over melompati fungsi tanpa menjalankannya. Fungsinya tetap jalan sampai selesai. Kalau ada breakpoint di dalamnya, DevTools tetap berhenti di sana.
- Breakpoint biasa di dalam loop panjang. Pakai conditional breakpoint, misalnya
i === 847atauNumber.isNaN(total). debugger;ikut ke production. Semua orang yang membuka DevTools ikut terhenti di sana. Hapus sebelum commit, atau pakai breakpoint dan logpoint yang hidup di DevTools.- Di latihan: mencatat semua langkah.
stephanya mencatat kalau breakpoint-nya ada dan kondisinyatrue. Baris tanpa breakpoint (seperti baris 15) gak pernah jadi hit.
TL;DR: Klik nomor baris di panel Sources untuk memasang breakpoint (atau tulis debugger;). Saat paused, baris yang disorot belum jalan; Scope menunjukkan nilai variabel (Local, Block, Script, Global) dan Call Stack menunjukkan siapa memanggil siapa, dibaca dari atas. Resume (F8) lanjut ke breakpoint berikutnya, Step over (F10) menjalankan fungsi tanpa masuk, Step into (F11) masuk ke fungsinya, Step out (Shift+F11) keluar ke pemanggilnya. Conditional breakpoint cuma berhenti kalau kondisinya true, logpoint mencetak ke Console tanpa berhenti, dan dua-duanya gak mengubah file kamu. Di program contoh, breakpoint di dalam hitungDiskon menunjukkan persen: undefined untuk Pensil, dan itu sumber NaN-nya.