Namanya program, pasti ada saatnya ada yang meleset. User mengetik teks padahal kamu menunggu angka, file yang dicari ternyata nggak ada, server membalas data yang nggak masuk akal, atau sebuah data yang kamu kira pasti ada malah ternyata undefined. Ketika hal seperti itu terjadi, JavaScript akan melempar error — dan kalau nggak ada yang menangkapnya, error itu langsung menghentikan skripmu di tempat. Kabar baiknya, error bukan berarti kamu nulis kode jelek. Error adalah bagian yang wajar dan memang sudah diperkirakan dari setiap program betulan, dan JavaScript memberi kamu cara yang rapi untuk menghadapinya: try...catch.
Di artikel ini kamu bakal belajar cara menangkap error sebelum ia bikin halamanmu crash, cara membuat dan melempar error sendiri saat ada yang salah, gunanya blok finally, plus beberapa kebiasaan yang membedakan kode rapuh dari kode yang tetap tangguh saat ditekan. Kalau kamu sudah melewati fungsi serta array dan objek, berarti kamu sudah siap untuk topik ini.
Apa itu error sebenarnya
Saat JavaScript ketemu sesuatu yang nggak bisa ia tangani, ia akan melempar error. Error itu sebenarnya sebuah objek — biasanya instance dari Error — yang membawa informasi tentang apa yang salah. Kalau kodemu nggak menangkapnya, error itu naik terus ke atas dan skripmu berhenti, lalu kamu bakal lihat pesan merah di konsol browser.
Ini cara paling gampang untuk memunculkan satu error:
const user = null;
console.log(user.name);
// TypeError: Cannot read properties of null (reading 'name')
user bernilai null, jadi nggak ada .name yang bisa dibaca. JavaScript melempar TypeError, dan semua kode setelah baris itu nggak akan pernah jalan. Tanpa penanganan error, satu nilai yang salah saja bisa merobohkan satu fitur utuh.
Sebuah objek error punya dua property yang bakal terus kamu pakai:
name— jenis error-nya, misalnya"TypeError"atau"RangeError".message— penjelasan yang bisa dibaca manusia soal apa yang terjadi.
const err = new Error("Ada yang rusak");
console.log(err.name); // "Error"
console.log(err.message); // "Ada yang rusak"
Blok try…catch
Alat utama untuk menangani error adalah try...catch. Kode yang berisiko kamu taruh di dalam try. Kalau ada apa-apa di sana yang melempar error, JavaScript langsung lompat ke blok catch alih-alih crash — dan menyerahkan objek error-nya ke kamu supaya kamu sendiri yang menentukan langkah selanjutnya:
try {
const user = null;
console.log(user.name); // melempar TypeError
console.log("Baris ini nggak akan pernah jalan");
} catch (error) {
console.log("Ada yang salah:", error.message);
}
console.log("Programnya tetap jalan terus.");
Perhatikan dua hal. Pertama, begitu user.name melempar error, sisa blok try langsung dilewati — "Baris ini nggak akan pernah jalan" memang nggak pernah tercetak. Kedua, programnya selamat: console.log yang terakhir tetap jalan normal. Justru itulah inti dari semuanya. Daripada skripnya mati, kamu menangkap masalahnya lalu lanjut.
Variabel di catch (error) itu adalah objek error yang barusan dilempar. Kamu bebas memberinya nama apa saja (err, e, error), tapi pilih yang jelas. Dari situ kamu bisa membaca .message, .name, dan lainnya.
Catch tanpa variabel itu boleh
Sejak ES2019, kamu boleh menghilangkan variabel error-nya sama sekali kalau memang nggak butuh: catch { ... }. Ini berguna saat kamu cuma mau bereaksi terhadap fakta bahwa ada yang gagal, tanpa peduli detailnya — misalnya untuk jatuh ke nilai default. Tapi biasanya kamu justru butuh error itu, minimal untuk dicatat ke log, jadi memakai catch (error) adalah pilihan default yang lebih aman.
Melempar error sendiri
try...catch bukan cuma untuk menangkap error yang dibuat JavaScript untukmu. Kamu juga bisa melempar error sendiri pakai keyword throw, kapan pun kodemu mendeteksi situasi yang menurutmu nggak sah. Begini caranya kamu menegakkan aturanmu sendiri.
Secara teknis kamu bisa melempar nilai apa saja, tapi sebaiknya kamu selalu melempar objek Error (atau turunannya). Objek error membawa stack trace dan berperilaku konsisten di mana-mana:
function setUmur(umur) {
if (typeof umur !== "number" || Number.isNaN(umur)) {
throw new Error("Umur harus berupa angka");
}
if (umur < 0) {
throw new Error("Umur nggak boleh negatif");
}
return umur;
}
try {
setUmur(-5);
} catch (error) {
console.log(error.message); // "Umur nggak boleh negatif"
}
Saat throw dijalankan, perilakunya sama persis dengan error bawaan: eksekusi berhenti di titik itu dan lompat ke catch terdekat. Dengan begini kamu bisa menolak input yang buruk secara lantang dan sedari awal, alih-alih membiarkan nilai yang salah diam-diam mengalir lebih dalam ke programmu lalu memicu kegagalan yang membingungkan di kemudian hari.
Lempar objek Error, bukan string
JavaScript membolehkan kamu menulis throw "Umur tidak valid" — melempar string biasa. Jangan. String yang dilempar nggak punya .message, nggak punya .name, dan nggak punya stack trace, jadi proses debugging jadi menyiksa dan kode mana pun yang mengharapkan error.message bakal rusak. Selalu lempar new Error("...") (atau jenis error yang lebih spesifik). Cuma butuh beberapa karakter tambahan, tapi menyelamatkanmu dari pusing yang sungguhan.
Blok finally
Kadang ada pembersihan yang harus dijalankan apa pun yang terjadi — entah kodenya berhasil atau gagal. Menutup koneksi, menyembunyikan spinner loading, mengaktifkan kembali sebuah tombol. Nah, untuk itulah blok opsional finally ada. Ia jalan setelah try/catch, tanpa kecuali:
function muatData() {
tampilkanSpinner();
try {
const data = ambilSesuatu(); // bisa melempar error
return data;
} catch (error) {
console.log("Gagal memuat:", error.message);
return null;
} finally {
sembunyikanSpinner(); // jalan entah berhasil atau gagal
}
}
Entah ambilSesuatu() berhasil atau melempar error, spinner-nya tetap disembunyikan. Blok finally ini jalan bahkan kalau blok try atau catch menjalankan return. Jaminan itulah alasan ia diciptakan: ia jadi tempat yang andal untuk logika “selalu lakukan ini di akhir”, supaya kamu nggak mungkin lupa membersihkan keadaan di salah satu jalur.
Jenis-jenis error yang bakal kamu temui
JavaScript punya beberapa jenis error bawaan, semuanya turunan dari Error dasar. Mengenalnya membantu kamu membaca pesan error lebih cepat dan bereaksi lebih tepat. Yang paling sering kamu temui:
TypeError— sebuah nilai ternyata bukan tipe yang kamu harapkan. Membaca property darinull/undefined, atau memanggil sesuatu yang bukan fungsi. Sejauh ini paling sering muncul dalam kode sehari-hari.ReferenceError— kamu memakai variabel yang nggak ada (sering kali gara-gara salah ketik nama).SyntaxError— kodenya sendiri yang salah bentuk. Ini biasanya bikin file-nya nggak bisa jalan sama sekali, jadi kamu nggak bisacatchkesalahan sintaksmu sendiri — tapiJSON.parseatas input yang buruk melemparSyntaxErroryang bisa kamu tangkap.RangeError— sebuah nilai berada di luar rentang yang diizinkan, misalnya panjang array yang nggak valid.
Kamu bisa mengecek jenis error yang ketangkap pakai instanceof, yang lebih bersih dan lebih aman ketimbang membandingkan string name:
try {
JSON.parse("{ ini bukan json valid }");
} catch (error) {
if (error instanceof SyntaxError) {
console.log("Itu bukan JSON yang valid.");
} else {
throw error; // lempar ulang apa pun yang nggak kita duga
}
}
Baris else { throw error; } itu kebiasaan kecil tapi penting: telan hanya error yang benar-benar kamu tahu cara menanganinya, lalu lempar ulang sisanya supaya nggak tersembunyi. Sebuah catch yang diam-diam melahap semua error adalah salah satu cara paling gampang untuk mengubur bug sungguhan.
Contoh realistis: mem-parsing JSON dengan aman
JSON.parse adalah salah satu tempat paling umum kode betulan melempar error. Ia menunggu string JSON yang valid, dan begitu menerima sesuatu yang salah bentuk, ia langsung melempar SyntaxError. Kalau data itu datang dari user, dari file, atau dari API, kamu nggak bisa berasumsi ia selalu rapi — jadi bungkus dengan try...catch:
function parseConfig(text) {
try {
return JSON.parse(text);
} catch (error) {
console.warn("Config nggak valid, pakai default:", error.message);
return { theme: "light", language: "id" };
}
}
const bagus = parseConfig('{ "theme": "dark" }');
console.log(bagus.theme); // "dark"
const buruk = parseConfig("waduh bukan json");
console.log(buruk.theme); // "light" (jatuh ke default)
Daripada membiarkan satu string yang buruk merobohkan seluruh aplikasi, parseConfig menangkap kegagalannya dan mengembalikan nilai default yang masuk akal. User nggak pernah lihat halaman yang rusak — mereka cuma dapat pengaturan standar. Itulah penanganan yang rapi dalam praktiknya: antisipasi bahwa input mungkin salah, dan siapkan rencana saat itu betul-betul terjadi.
JSON formatter membantu menemukan masalahnya
Saat JSON.parse terus melempar error dan kamu nggak ngeh kenapa, tempel string-nya ke alat yang merapikan dan mengeceknya — koma yang hilang atau tanda kutip nyasar bakal langsung kelihatan. JSON formatter ini pas banget untuk itu: ia merapikan JSON yang valid dan menunjuk di mana JSON yang nggak valid rusak, jadi kamu bisa membetulkan sumbernya alih-alih menebak-nebak.
Kapan pakai try…catch (dan kapan tidak)
try...catch itu ampuh, tapi ia bukan jawaban untuk setiap kemungkinan masalah. Pakai ia untuk situasi yang memang di luar kendalimu — hal-hal yang nggak bisa kamu cegah cuma dengan menulis kode yang lebih hati-hati:
- Mem-parsing data yang bukan kamu yang buat (
JSON.parse, input user). - Permintaan jaringan yang mungkin gagal (ini bakal terus kamu temui begitu sampai di
fetch). - Operasi apa pun yang menurut dokumentasinya bisa melempar error.
Yang try...catch bukan untuknya adalah menggantikan pengecekan biasa. Kalau sebuah nilai mungkin kosong, sebuah if lebih jelas dan lebih murah ketimbang membungkus semuanya dalam try:
// Jangan andalkan try...catch untuk yang seperti ini:
function getNama(user) {
if (!user) {
return "Tamu";
}
return user.name;
}
Pengecekan if biasa menyampaikan maksudmu secara langsung dan jalan lebih cepat. Patokan praktisnya: pakai if untuk menjaga dari kondisi yang bisa kamu perkirakan dan uji, dan pakai try...catch untuk kegagalan yang nggak bisa kamu tebak baris per baris — operasi yang melempar error dengan sendirinya.
Jangan pernah membungkam error dengan catch kosong
Pola paling merusak dalam penanganan error adalah blok catch yang kosong:
try {
lakukanSesuatuPenting();
} catch (error) {
// kosong di sini
}Ini menelan error-nya lalu pura-pura nggak ada apa-apa. Operasinya gagal, tapi programmu bertingkah seolah berhasil — jadi bug aslinya muncul di tempat yang jauh, jauh kemudian, tanpa jejak dari mana ia bermula. Paling minimal, catat error-nya ke log. Lebih bagus lagi, tangani, tampilkan sesuatu yang berguna ke user, atau lempar ulang. catch kosong nggak membereskan masalah; ia menyembunyikannya.
Penutup
Sekarang kamu sudah pegang dasar yang kokoh untuk menangani hal-hal yang meleset:
- Sebuah error adalah objek (biasanya
Error) dengannamedanmessage. Kalau nggak ditangkap, ia menghentikan skripmu. try...catchmenjalankan kode berisiko ditry; kalau melempar error, kendali lompat kecatch (error)alih-alih crash, dan programmu tetap jalan.throw new Error("...")memungkinkanmu memunculkan error sendiri untuk menolak situasi yang nggak sah. Selalu lempar objekError, jangan pernah string biasa.finallyjalan setelahtry/catchapa pun yang terjadi — tempat yang andal untuk pembersihan.- Jenis bawaan seperti
TypeError,ReferenceError, danSyntaxErrormemberi tahu apa yang rusak; pakaiinstanceofuntuk bereaksi ke jenis tertentu dan lempar ulang yang nggak kamu duga. - Pakai
try...catchuntuk kegagalan di luar kendalimu (parsing, jaringan), dan pengecekanifbiasa untuk kondisi yang bisa kamu perkirakan. Jangan pernah membiarkancatchkosong.
Penanganan error adalah hal yang mengubah sebuah demo jadi sesuatu yang benar-benar bisa diandalkan orang. Dengan alat-alat ini, kamu bisa membiarkan sebagian kodemu gagal tanpa menjatuhkan keseluruhannya. Berikutnya kita bahas JSON — format data yang barusan kamu tangkap error-nya — dan begitu kamu nyaman di sana, lanjut ke kode asinkron dengan promise dan fetch, tempat try...catch jadi teman sehari-hari.