Breakpoints & Stepping — Debugging

Breakpoints & Stepping Breakpoints memungkinkan kamu menghentikan sementara eksekusi kode di baris tertentu, lalu memeriksa state aplikasi (variabel, call…

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 dalam hitungDiskon, 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

  1. Buka DevTools (F12, atau Ctrl+Shift+I; di Mac Cmd+Option+I), lalu pilih panel Sources.
  2. Di daftar file sebelah kiri, buka app.js.
  3. Klik nomor baris 9. Muncul penanda biru: itu breakpoint-nya.
  4. 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

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.

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

⚠️ Jebakan yang sering ketemu

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.

Yang akan kamu pelajari