Error yang tertangkap lewat try/catch menyertakan pesan rapi, sedangkan bug yang lolos hanya menyisakan perilaku program yang salah. Topik ini menata alur debugging di DevTools, mulai dari membaca pesan error, berhenti di breakpoint untuk memeriksa keadaan program, sampai memakai konsol di luar console.log untuk menyajikan data. Bagian panel dan breakpoint dijelaskan sebagai prosedur di Chrome DevTools, sedangkan demo konsol dijalankan di Node.js karena API-nya sama.
Membaca pesan error di DevTools#
Pesan error di konsol DevTools terdiri atas tiga bagian, yaitu jenis error, isi pesan, lalu lokasi berkas dan baris. Baris pertama pada pesan TypeError: Cannot read properties of undefined (reading 'nama') misalnya sudah menjawab apa yang rusak, sedangkan baris-baris di bawahnya berupa call stack, yaitu urutan pemanggilan fungsi yang berujung pada error tersebut. Prosedur berikut biasanya dipakai untuk menelusuri error yang belum tertangkap di Chrome.
- Buka DevTools dengan tombol F12 atau menu browser, lalu pindah ke tab Console.
- Ulangi aksi yang memunculkan error, dan pesan merah akan muncul di konsol.
- Baca baris pertamanya, jenis error di kiri dan pesannya di sebelah kanan.
- Klik tautan berkas beserta nomor barisnya, lalu panel Sources membuka berkas itu tepat di baris yang dimaksud.
- Perluas bagian call stack di bawah pesan untuk melihat fungsi mana yang memanggil fungsi yang gagal.
Nomor baris yang ditunjuk pesan belum tentu menjadi penyebabnya, karena baris itu hanya tempat kegagalan terlihat, sedangkan penyebabnya bisa jadi data yang salah sejak jauh di atas. Itulah alasan call stack perlu dibaca, karena call stack menunjukkan jalur yang dilalui eksekusi sebelum berhenti. Node.js mencetak pesan serupa pada terminal, lengkap dengan nomor berkas dan barisnya, sehingga kebiasaan membaca pesan ini berlaku di dua lingkungan sekaligus. Properti error.stack menyediakan teks yang sama lewat kode, meskipun biasanya cukup membacanya langsung dari konsol.
Breakpoint dan panel Sources#
Breakpoint menghentikan eksekusi pada baris tertentu sehingga keadaan seluruh variabel dapat diperiksa pada saat itu juga. Panel Sources di Chrome menyediakan alur pemasangannya dengan langkah-langkah berikut.
- Buka tab Sources, lalu pilih berkas JavaScript dari pohon berkas di sebelah kiri.
- Klik nomor baris tempat eksekusi ingin dihentikan, penanda biru akan muncul.
- Muat ulang halaman atau picu aksi yang menjalankan baris tersebut.
- Amati panel di sebelah kanan, bagian Watch menampilkan nilai ekspresi yang dipantau, Call Stack menampilkan urutan pemanggilan, dan Scope menampilkan isi variabel lokal.
- Lanjutkan eksekusi dengan Resume atau berjalan per baris dengan Step over dan Step into, pintasannya masing-masing F8, F10, dan F11 di Chrome.
- Klik kanan nomor baris lalu pilih breakpoint bersyarat bila bug hanya muncul pada nilai tertentu, misalnya hanya saat
idbernilai tertentu.
Alternatif tanpa menyentuh panel adalah debugger statement, yaitu perintah debugger yang ditulis di dalam kode. Eksekusi berhenti di baris itu dengan perilaku yang sama seperti breakpoint, tetapi hanya bila DevTools sedang terbuka.
// tidak-dijalankan
function hitungTotal(item) {
debugger; // eksekusi berhenti di baris ini bila DevTools terbuka
return item.reduce((total, entri) => total + entri.harga, 0);
}Berbeda dari breakpoint yang tersimpan di browser, perintah debugger tertulis di dalam kode, sehingga baris yang tertinggal menghentikan halaman pada setiap pemuatan bila DevTools terbuka. Baris ini perlu dihapus sebelum kode dipakai bersama, dan pencarian teks “debugger” pada berkas yang diedit cukup untuk memastikannya. Untuk memeriksa nilai tanpa menghentikan eksekusi sama sekali, Chrome menyediakan logpoint melalui menu klik kanan pada nomor baris. Logpoint mencetak ekspresi ke konsol setiap kali barisnya dilewati.
Konsol di luar log#
Konsol memiliki beberapa metode yang menyajikan data lebih terbaca daripada console.log biasa, dan semuanya berjalan di Node.js maupun browser. Metode pertama adalah console.table, yang merender array berisi object menjadi tabel dengan setiap object sebagai barisnya.
const rapor = [
{ nama: "Citra", nilai: 88 },
{ nama: "Budi", nilai: 92 },
];
console.table(rapor);┌─────────┬─────────┬───────┐
│ (index) │ nama │ nilai │
├─────────┼─────────┼───────┤
│ 0 │ 'Citra' │ 88 │
│ 1 │ 'Budi' │ 92 │
└─────────┴─────────┴───────┘Tabel di atas membuat perbandingan antar object terlihat sekaligus, sesuatu yang sulit didapat dari deretan console.log. Metode kedua adalah console.group yang mengelompokkan beberapa baris log di bawah satu judul, berguna ketika satu proses mencetak banyak baris sekaligus.
console.group("Laporan");
console.log("total: 3");
console.group("Detail");
console.log("aktif: 2");
console.groupEnd();
console.log("selesai");
console.groupEnd();
console.log("di luar");Laporan
total: 3
Detail
aktif: 2
selesai
di luarPengelompokan bisa bersarang, ditandai dengan grup Detail yang menjorok di dalam grup Laporan. Metode ketiga mengukur durasi. Pasangan console.time dan console.timeEnd mencetak selisih waktunya dalam milidetik.
// tidak-dijalankan
console.time("urutkan");
const nama = ["Citra", "Budi", "Ani"].sort();
console.timeEnd("urutkan");Blok ini sengaja tidak disertai keluaran karena angka milidetiknya berubah pada setiap eksekusi, dengan bentuk kira-kira urutkan: 0.2ms. Perbedaan antar eksekusi memang wajar karena pengukuran waktu selalu menyertakan keadaan mesin saat itu. Yang penting adalah urutan besarnya, bukan angka persisnya.
Alur kerja debugging#
Perkakas di atas menyusun alur kerja debugging yang berulang, dari reproduksi sampai verifikasi perbaikan. Urutannya sebagai berikut.
- Reproduksi bug dengan langkah yang sama setiap kali, karena bug yang tidak bisa dipicu juga tidak bisa diperiksa.
- Baca pesan errornya, lalu klik tautan lokasi untuk melompat ke baris yang gagal.
- Pasang breakpoint sedekat mungkin dengan lokasi itu, atau sedikit di depannya agar keadaan sebelum kegagalan turut terlihat.
- Periksa nilai lewat Watch dan Scope, lalu susun hipotesis tentang keadaan mana yang tidak sesuai harapan.
- Perbaiki kodenya, muat ulang, dan jalankan ulang langkah reproduksi untuk memastikan bug hilang tanpa memunculkan yang baru.
Alur ini mencegah kebiasaan yang sering membuang waktu, yaitu memperbaiki kode sebelum keadaan program benar-benar terlihat. Tebakan tanpa dukungan data sering menghasilkan perubahan kode yang tidak menyentuh penyebabnya, dan bug berpindah ke bentuk yang lebih samar. Dengan breakpoint, hipotesis diuji lewat nilai yang nyata pada momen kejadian, sehingga perbaikan yang ditulis didasarkan pada fakta. Konsol di luar console.log melengkapi alur ini ketika bug hanya muncul pada data yang panjang, karena tabel dan pengelompokan membuat data itu tetap terbaca.
Ringkasan#
- Pesan error dibaca dari jenisnya, isinya, lalu lokasinya, dan tautan lokasinya membuka berkas di panel Sources.
- Breakpoint menghentikan eksekusi sehingga Watch, Call Stack, dan Scope menampilkan keadaan program pada momen kejadian.
- Perintah
debuggerbekerja seperti breakpoint dan hanya aktif saat DevTools terbuka, sehingga barisnya wajib dibersihkan sebelum kode dipakai bersama. console.table,console.group, dan pasanganconsole.timedenganconsole.timeEndmenyajikan data serta durasi dengan lebih terbaca daripada deretanconsole.log.
Referensi#
- Debug JavaScript — Chrome DevTools — Panduan resmi alur debugging di panel Sources DevTools.
- Pause your code with breakpoints — Chrome DevTools — Jenis breakpoint, breakpoint bersyarat, dan pintasan langkah eksekusi.
- Console — MDN Web Docs — Metode console selain log, termasuk table, group, dan time.