Cara Debugging JavaScript melalui DevTools
Menelusuri bug filter artikel secara sistematis dari gejala hingga penyebab, tanpa menebak-nebak atau memenuhi kode dengan console.log.
Debugging bukan kegiatan mencoba perubahan acak sampai error menghilang. Workflow yang baik mengubah laporan “filternya rusak” menjadi langkah yang dapat direproduksi, mempersempit lokasi, menguji hipotesis, lalu memastikan perbaikannya tidak menimbulkan regresi.
- Filter artikel bekerja pada pemuatan pertama.
- Setelah pengguna mengetik lalu mengganti kategori, hasil kadang kosong.
- Tidak selalu ada error merah di Console.
- Kita akan memeriksa state, event, dan urutan eksekusi.
Tulis langkah reproduksi yang deterministik
Catat URL, browser, ukuran layar, data awal, langkah, hasil aktual, dan hasil yang diharapkan. Jika bug hanya muncul sesekali, cari variabel seperti kecepatan jaringan, cache, urutan klik, atau data tertentu.
Lingkungan: Chrome, viewport 375px
Data awal: kategori = Semua, query kosong
Langkah:
1. Ketik "grid"
2. Ganti kategori menjadi JavaScript
3. Hapus query dengan cepat
Aktual: daftar kosong
Harapan: semua artikel JavaScript tampil
Reproduksi yang jelas memungkinkan kita mengetahui apakah sebuah perubahan benar-benar memperbaiki bug.
Baca error lengkap, bukan hanya baris terakhir
Error biasanya berisi tipe, pesan, file, nomor baris, dan stack trace. Baris teratas stack menunjukkan lokasi error dilempar, sedangkan frame berikutnya menjelaskan jalur pemanggilan. Klik tautan file untuk membuka Sources pada baris tersebut.
TypeError: Cannot read properties of null (reading 'value')
at updateFilters (filters.js:42)
at HTMLSelectElement.<anonymous> (filters.js:71)
Pesan ini tidak otomatis berarti baris 42 adalah akar masalah. Selector mungkin salah, script berjalan pada halaman yang tidak mempunyai field, atau elemen diganti setelah referensi disimpan.
Gunakan breakpoint sebelum menambah log
Pasang line-of-code breakpoint di awal handler kategori. Ulangi langkah reproduksi, lalu lihat Scope. Periksa nilai query, category, page, dan items pada saat bug terjadi. Gunakan Step over untuk bergerak per pernyataan dan Step into ketika perlu masuk ke function yang dipanggil.
Conditional breakpoint berguna jika bug hanya muncul pada kombinasi tertentu:
// Kondisi breakpoint di DevTools
category === "JavaScript" && query === ""
Logpoint dapat mencatat nilai tanpa mengubah source dan tanpa menghentikan eksekusi. Ini lebih bersih daripada menambahkan banyak console.log() lalu lupa menghapusnya.
Periksa perubahan state dari waktu ke waktu
Pada kasus filter, bug dapat berasal dari closure yang menyimpan page lama atau timeout yang selesai dalam urutan berbeda. Tambahkan Watch expression untuk variabel penting dan lihat kapan nilainya berubah.
function scheduleUpdate(filters) {
clearTimeout(updateTimer);
updateTimer = setTimeout(() => {
renderResults(filters);
}, 200);
}
Jika object filters dimutasi sebelum timeout berjalan, callback membaca nilai terbaru, bukan snapshot ketika dijadwalkan. Buat salinan eksplisit jika itu yang dibutuhkan.
function scheduleUpdate(filters) {
clearTimeout(updateTimer);
const snapshot = { ...filters };
updateTimer = setTimeout(() => {
renderResults(snapshot);
}, 200);
}
Gunakan Event Listener Breakpoints
Jika tidak tahu handler mana yang merespons klik atau change, aktifkan breakpoint pada kategori event di Sources. Browser berhenti ketika listener dijalankan dan Call Stack memperlihatkan file pemiliknya. Fitur ini sangat membantu pada proyek yang memasang listener melalui beberapa module.
Untuk perubahan DOM misterius, pilih elemen di Elements lalu gunakan “Break on” untuk subtree modifications, attribute modifications, atau node removal. DevTools berhenti pada JavaScript yang melakukan perubahan tersebut.
Network adalah bagian dari debugging JavaScript
Ketika data tidak muncul, periksa apakah request benar-benar dikirim, URL dan method benar, status respons, response body, timing, serta apakah browser menggunakan cache. Error HTTP tidak selalu membuat fetch() reject; status 404 atau 500 tetap perlu diperiksa melalui response.ok.
async function loadArticles() {
const response = await fetch("/data/articles.json");
if (!response.ok) {
throw new Error(`Gagal memuat artikel: HTTP ${response.status}`);
}
return response.json();
}
Bedakan exception sinkron dan asynchronous
try {
loadArticles(); // Promise tidak di-await
} catch (error) {
// Tidak menangkap rejection dari Promise di atas
}
try {
await loadArticles();
} catch (error) {
showError(error);
}
Aktifkan “Pause on exceptions” untuk berhenti ketika exception dibuat. Mode caught exceptions berguna jika library menangkap error terlalu cepat, tetapi dapat menghasilkan banyak pause dari kode pihak ketiga; gunakan ignore list untuk menjaga fokus pada source sendiri.
Kurangi kasus dengan strategi pembagian
Jika bug berada pada fungsi besar, nonaktifkan setengah jalur secara sementara atau uji function kecil secara terpisah. Jangan langsung menulis ulang seluruh module karena gejala dapat hilang tanpa kita memahami penyebabnya.
- Apakah bug terjadi tanpa debounce?
- Apakah terjadi ketika category tetap “Semua”?
- Apakah terjadi dengan satu item data?
- Apakah terjadi jika render diganti dengan output sederhana?
- Apakah state sudah salah sebelum render atau baru salah di DOM?
Perbaiki penyebab dan tambahkan guard
Misalnya penyebabnya adalah page pagination tidak kembali ke 1 setelah query berubah. Perbaikan bukan menambah hasil palsu ketika daftar kosong, tetapi mereset page pada event yang benar dan membatasi page setelah jumlah hasil dihitung.
function applyFilters(nextFilters) {
state = {
...state,
...nextFilters,
page: 1
};
render();
}
Setelah itu tambahkan test atau minimal skenario regresi yang mengulangi kombinasi query, kategori, dan pagination.
Verifikasi lebih luas dari gejala awal
- Ulangi langkah bug persis seperti laporan.
- Uji query kosong, hasil kosong, karakter khusus, dan input cepat.
- Uji kategori lain dan halaman pagination terakhir.
- Periksa Console dan Network tetap bersih.
- Uji keyboard dan pembaca layar jika DOM atau fokus berubah.
- Jalankan pada mode jaringan lambat jika ada async flow.
- Baca diff agar tidak ada debug statement atau perubahan sampingan.