Error handling adalah fondasi penting dalam pengembangan JavaScript. Tanpa teknik penanganan error yang baik, aplikasi bisa crash, UI bisa freeze, dan pengguna bisa mengalami pengalaman yang buruk. Artikel ini membahas secara mendalam cara menangani error di JavaScript, mulai dari dasar try catch finally hingga penanganan error pada Promise dan Async/Await.
Agar mudah dipahami pemula, artikel ini disusun per bagian, lengkap dengan contoh, ilustrasi, dan best practice yang dapat langsung diterapkan.
Daftar isi
Baca juga: Asynchronous JavaScript: Callback, Promise, dan Async Await
Pengenalan Error Handling di JavaScript
Error handling di JavaScript adalah mekanisme untuk mendeteksi, menangkap, dan menangani error agar aplikasi tetap berjalan meskipun terjadi kesalahan. Dalam JavaScript, error bisa muncul karena berbagai hal: logika yang salah, nilai yang tidak sesuai, kesalahan sintaks, sampai masalah asynchronous seperti request API yang gagal.
Error handling memungkinkan developer:
- Menghindari aplikasi crash total
- Memberikan pesan error yang lebih ramah pengguna
- Melacak sumber error dengan jelas (stack trace)
- Memastikan proses tertentu tetap berjalan menggunakan finally
Dengan kata lain, error handling adalah “sabuk pengaman” dalam pemrograman JavaScript.
Kenapa Error Handling Penting
Tanpa error handling, sebuah error kecil bisa menghentikan seluruh jalannya aplikasi. Dalam aplikasi modern—terutama yang berjalan di browser—ini bisa sangat fatal.
Beberapa alasan utama kenapa error handling penting:
1. Menjaga pengalaman pengguna
Error yang tidak ditangani dapat membuat halaman kosong, tombol tidak bekerja, atau form gagal terkirim tanpa penjelasan. Dengan error handling, Anda bisa menampilkan pesan seperti:
“Oops, terjadi kesalahan. Coba lagi nanti.”
2. Mencegah aplikasi berhenti total
JavaScript menghentikan eksekusi suatu fungsi ketika error muncul. Jika tidak ditangani, error itu dapat menyebar ke bagian lain.
3. Membantu debugging
Dengan menangkap error, Anda bisa mencatat message, nama error, dan stack trace ke log atau server backend.
4. Penting untuk aplikasi asynchronous
Request API bisa gagal kapan saja. Promise bisa error. async/await bisa melempar exception. Tanpa error handling, Anda akan buta terhadap situasi tersebut.
Contoh Kasus Aplikasi Tanpa Error Handling
Bayangkan Anda memiliki fungsi sederhana yang mengambil data user dari API:
async function getUser() {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
console.log("User:", data.name);
}
getUser();Code language: JavaScript (javascript)
Apa yang terjadi jika:
- Koneksi internet lambat?
- Endpoint API sedang down?
- API mengembalikan struktur data berbeda?
- Server memberikan status 500?
Aplikasi langsung melempar error dan berhenti.
Di console Anda mungkin akan melihat:
Uncaught (in promise) TypeError: Failed to fetchCode language: JavaScript (javascript)
Dan proses console.log tidak akan berjalan. Jika ini terjadi pada aplikasi yang digunakan pelanggan, mereka akan merasa aplikasi “rusak”, padahal hanya kurang error handling.
Manfaat Error Handling untuk Pengembangan Web Modern
Error handling bukan lagi opsional dalam pengembangan web modern. Ada beberapa manfaat besar:
Aplikasi lebih stabil
Dengantry...catchdanfinally, setiap error dapat ditangani secara terkendali.Mudah di-maintain
Developer dapat dengan cepat mengetahui sumber masalah dari stack trace yang ditangkap.User lebih percaya pada aplikasi
Tidak ada yang suka aplikasi yang tiba-tiba tidak bekerja. Pesan error yang sopan jauh lebih baik daripada crash.Lebih aman
Error yang tidak ditangani kadang membuka celah bagi attacker untuk melihat informasi internal aplikasi.Wajib untuk fitur besar
Seperti:- API fetching
- Authentication
- Sistem pembayaran
- Pengolahan file
- Aplikasi realtime
Jadi, error handling adalah pondasi penting agar aplikasi tetap profesional, aman, dan nyaman digunakan.
Jenis-Jenis Error dalam JavaScript
Memahami jenis-jenis error di JavaScript sangat penting sebelum mempelajari cara menangani error dengan try…catch atau Promise. Setiap jenis error memiliki ciri dan penyebab yang berbeda. Dengan mengenal semuanya, proses debugging akan jauh lebih cepat dan efisien.
Syntax Error
Syntax Error terjadi ketika JavaScript tidak bisa memahami kode karena kesalahan penulisan. Ini seperti salah ketik yang membuat interpreter tidak bisa membaca instruksi.
Contoh kesalahan umum:
function sayHello() {
console.log("Hello"
}Code language: JavaScript (javascript)
Error yang muncul:
Uncaught SyntaxError: Unexpected token '}'Code language: JavaScript (javascript)
Ciri-ciri Syntax Error:
- Terjadi sebelum kode dijalankan.
- Biasanya disebabkan oleh kurung yang kurang, tanda kutip tidak lengkap, atau karakter ilegal.
- Dapat diketahui secara cepat oleh editor modern melalui highlight merah.
Syntax Error tidak bisa ditangani dengan try…catch, karena script tidak akan jalan sama sekali sebelum kesalahan diperbaiki.
Runtime Error
Runtime Error muncul saat kode sudah berjalan, tetapi ada sesuatu yang tidak valid.
Contoh:
let user = null;
console.log(user.name);Code language: JavaScript (javascript)
Error:
Uncaught TypeError: Cannot read properties of null (reading 'name')Code language: JavaScript (javascript)
Ciri-ciri:
- Terjadi ketika program sedang berjalan.
- Bisa ditangani dengan
try…catch. - Sering disebabkan oleh nilai yang tidak sesuai ekspektasi.
Runtime Error adalah jenis error yang paling sering dihadapi developer sehari-hari.
Logical Error
Logical Error adalah kesalahan logika dalam algoritma sehingga aplikasi menghasilkan output yang salah. Ini tidak menghasilkan pesan error otomatis, tapi hasilnya tidak sesuai.
Contoh:
function tambah(a, b) {
return a - b; // seharusnya a + b
}
console.log(tambah(5, 2)); // Output: 3 (salah)Code language: JavaScript (javascript)
Ciri-ciri:
- Tidak ada pesan error.
- Sangat sulit dideteksi.
- Biasanya ditemukan melalui testing atau pengecekan manual.
Logical Error adalah “musuh tersembunyi” karena tidak terlihat di console.
TypeError, ReferenceError, RangeError, EvalError, URIError
JavaScript memiliki banyak jenis error bawaan (built-in errors) yang muncul saat terjadi kondisi tertentu. Berikut penjelasan yang paling penting:
1. TypeError
Muncul ketika tipe data atau operasi tidak sesuai.
Contoh:
let fn = 123;
fn(); // memanggil angka sebagai fungsiCode language: JavaScript (javascript)
Error:
Uncaught TypeError: fn is not a functionCode language: JavaScript (javascript)
2. ReferenceError
Terjadi saat variabel dipanggil tetapi tidak dideklarasikan.
console.log(name); // variabel tidak adaCode language: JavaScript (javascript)
Error:
Uncaught ReferenceError: name is not definedCode language: JavaScript (javascript)
3. RangeError
Biasanya muncul saat nilai berada di luar batas yang diperbolehkan, misalnya length array negatif.
let arr = new Array(-5);Code language: JavaScript (javascript)
Error:
Uncaught RangeError: Invalid array lengthCode language: JavaScript (javascript)
4. EvalError
Berkaitan dengan fungsi eval() (jarang muncul kecuali dalam implementasi lama).
5. URIError
Error yang muncul ketika fungsi decode/encode URI berhadapan dengan karakter ilegal.
decodeURIComponent("%");Code language: JavaScript (javascript)
Error:
Uncaught URIError: URI malformedCode language: JavaScript (javascript)
Cara Membaca Pesan Error di Console
Salah satu keahlian dasar developer adalah membaca error di DevTools.
Format umum error:
TypeError: Cannot read properties of undefined (reading 'length')
at getUserName (app.js:12)
at main (app.js:22)Code language: JavaScript (javascript)
Penjelasannya:
TypeError→ jenis errorCannot read properties…→ pesan errorat getUserName (app.js:12)→ lokasi error (file + baris)at main (app.js:22)→ fungsi yang memanggilnya
Tips membaca error:
- Fokus pada baris pertama (jenis + pesan).
- Cek baris file yang ditunjuk.
- Lihat stack trace untuk mengetahui alur error.
- Jika error terkait Promise, sering muncul label:
Uncaught (in promise)
Error Stack Trace dan Artinya
Stack trace adalah daftar urutan fungsi yang dieksekusi hingga terjadi error. Ini sangat membantu debugging karena memperlihatkan jalan lengkap eksekusi program.
Contoh stack trace:
TypeError: Cannot read properties of undefined (reading 'length')
at getUserName (app.js:12)
at main (app.js:22)Code language: JavaScript (javascript)
Cara membacanya:
- Baris pertama menunjukkan pesan error.
- Baris selanjutnya menunjukkan jejak fungsi dari bawah ke atas.
- Fungsi paling bawah di daftar adalah pemicu awal error.
Manfaat stack trace:
- Mengetahui asal-usul error.
- Memudahkan debugging.
- Sangat penting dalam error handling pada Promise dan async/await.
Dasar Try, Catch, Finally
Struktur try…catch…finally adalah fondasi utama dalam error handling JavaScript. Dengan memahami bagian-bagiannya, Anda dapat mencegah aplikasi crash, memberikan pesan error yang lebih jelas, dan menjaga proses penting tetap berjalan.
Cara Kerja Try
Bagian try adalah tempat Anda menulis kode yang berpotensi menghasilkan error. JavaScript akan menjalankan kode dalam blok try seperti biasa, tetapi jika terjadi kesalahan, eksekusi akan langsung dialihkan ke catch.
Contoh sederhana:
try {
let data = JSON.parse("ini bukan JSON");
console.log(data);
}Code language: JavaScript (javascript)
Apa yang terjadi?
- JavaScript mencoba menjalankan kode.
- Saat mencapai
JSON.parse, terjadi error. - Eksekusi langsung dihentikan.
- Baris setelah error tidak dijalankan.
Program melompat ke blok catch.
Tujuan try:
- Mendeteksi potensi error.
- Mengelompokkan blok kode kritis.
- Mencegah aplikasi berhenti total.
Fungsi Catch
Blok catch digunakan untuk menangani error yang terjadi dalam try. Di dalamnya, Anda dapat:
- Menampilkan pesan error
- Menyimpan error ke log server
- Menampilkan notifikasi ke user
- Melakukan recovery (fallback)
Contoh:
try {
let result = number.toUpperCase(); // number tidak didefinisikan
} catch (error) {
console.error("Terjadi error:", error.message);
}Code language: JavaScript (javascript)
Output:
Terjadi error: number is not defined
catch menerima satu parameter, biasa diberi nama:
- error
- err
- e
Objek error biasanya memiliki:
name→ jenis error (TypeError, ReferenceError, dll)message→ deskripsi errorstack→ jejak fungsi penyebab error
Yang membuat catch sangat penting:
- Anda dapat menangani error tanpa menghentikan program.
- Cocok untuk debugging dan logging.
- Bisa digunakan untuk memberi fallback, misalnya:
let username;
try {
username = getUserName();
} catch (e) {
username = "Guest"; // fallback
}Code language: JavaScript (javascript)
Kapan Finally Dijalankan
finally adalah blok yang selalu dijalankan, terlepas dari apakah terjadi error atau tidak. Ini berguna untuk:
- Membersihkan resource (misal: koneksi database)
- Menghentikan loading spinner
- Menutup modal
- Mengembalikan state aplikasi
Contoh:
try {
console.log("Memproses data...");
throw new Error("Gagal memproses");
} catch (err) {
console.log("Error:", err.message);
} finally {
console.log("Selesai. Membersihkan...");
}Code language: JavaScript (javascript)
Output:
Memproses data...
Error: Gagal memproses
Selesai. Membersihkan...
finally tetap dijalankan meskipun:
- Ada error
- Tidak ada error
- Ada
returndi dalamtry - Ada
returndi dalamcatch
Bahkan:
Perilaku Try/Catch pada Browser vs Node.js
Secara konsep, try/catch sama di keduanya, namun ada beberapa perbedaan kecil akibat lingkungan eksekusi.
Browser
- Error sering muncul akibat DOM, event handler, atau API browser.
- Error pada asynchronous (Promise) tidak tertangkap otomatis oleh
try/catchtanpaawait. - Console browser menampilkan error dengan link file dan nomor baris.
Node.js
- Sering berkaitan dengan modul, file system, dan proses server.
- Error fatal dapat menghentikan proses Node.
- Menawarkan fitur tambahan seperti process.on(‘uncaughtException’).
Contoh di Node.js:
try {
require("file-yang-tidak-ada");
} catch (e) {
console.error("Error module:", e.message);
}Code language: JavaScript (javascript)
Contoh Kasus Simple
Contoh praktis error handling untuk pemula:
Kasus: Membaca input user yang tidak valid
function hitungDiskon(harga) {
try {
if (typeof harga !== "number") {
throw new Error("Harga harus berupa angka");
}
let diskon = harga * 0.2;
return diskon;
} catch (error) {
console.error("Error:", error.message);
return 0; // fallback
} finally {
console.log("Fungsi hitungDiskon selesai dijalankan.");
}
}
console.log(hitungDiskon(100000)); // 20000
console.log(hitungDiskon("seratus ribu")); // Error → 0Code language: JavaScript (javascript)
Penjelasan:
- Error ditangkap di
catch. - Program tetap berjalan normal.
finallytetap dijalankan, bahkan jika input tidak valid.
Throw: Membuat Error Sendiri
Selain menangani error, JavaScript memungkinkan kita membuat error secara manual menggunakan throw. Fitur ini penting untuk membuat validasi yang lebih kuat, menjaga kualitas data, dan mengontrol alur program dengan baik. Dengan throw, kita bisa menentukan kapan sebuah kondisi dianggap bermasalah dan harus dihentikan.
Kapan Menggunakan throw
Gunakan throw ketika Anda ingin:
1. Menghentikan eksekusi secara terkontrol
Jika ada kondisi yang tidak valid, Anda bisa segera menghentikan fungsi tanpa menunggu error alami muncul.
Contoh:
function bagi(a, b) {
if (b === 0) {
throw "Pembagian dengan nol tidak diperbolehkan!";
}
return a / b;
}
console.log(bagi(10, 2)); // 5
console.log(bagi(10, 0)); // ErrorCode language: JavaScript (javascript)
2. Memberikan pesan error yang lebih jelas
Error default JavaScript kadang tidak informatif. Dengan throw, Anda bisa membuat error yang mudah dipahami.
3. Melakukan validasi input
Validasi sangat umum dalam aplikasi web, seperti memeriksa email, nomor telepon, atau data form.
4. Mengontrol alur Promise dan async/await
Dalam async function, throw otomatis menghasilkan rejected Promise.
Contoh:
async function getUser() {
throw new Error("Token tidak valid");
}Code language: JavaScript (javascript)
5. Menghasilkan error yang bisa di-catch
Anda dapat menangkap error yang dilempar menggunakan try…catch.
throw vs throw new Error
Banyak pemula bingung: harus pakai throw "pesan" atau throw new Error("pesan")?
Keduanya bisa, tapi sangat berbeda.
throw “pesan”
Anda melempar nilai string biasa, bukan objek Error.
Contoh:
throw "Terjadi kesalahan";Code language: JavaScript (javascript)
Kekurangannya:
- Tidak memiliki
name - Tidak memiliki stack trace
- Sulit dideteksi dalam logging
- Tidak standar
throw new Error(“pesan”)
Cara yang direkomendasikan.
throw new Error("Data user tidak ditemukan");Code language: JavaScript (javascript)
Keuntungannya:
- Memiliki properti lengkap (
name,message,stack) - Mudah dilacak di console
- Bisa dibuat custom kelas error sendiri
- Sesuai standar industri
Perbandingan singkat
| Teknik | Dianjurkan? | Alasan |
|---|---|---|
throw "pesan" | Tidak | Tidak ada detail error, sulit dilacak |
throw new Error("pesan") | Ya | Lebih rapi, lengkap, standar |
throw new CustomError(...) | Sangat direkomendasikan | Untuk sistem error profesional |
Membuat Custom Validation Error
Anda bisa membuat kelas error sendiri dengan mewarisi dari Error. Ini sangat bermanfaat ketika Anda ingin membedakan berbagai jenis error (validasi, otorisasi, database, dll).
Contoh membuat class custom:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
function daftarUser(username) {
if (username.length < 3) {
throw new ValidationError("Username minimal 3 karakter!");
}
return "Pendaftaran berhasil";
}
try {
daftarUser("ab");
} catch (error) {
if (error instanceof ValidationError) {
console.error("Validasi gagal:", error.message);
} else {
console.error("Error lain:", error.message);
}
}Code language: JavaScript (javascript)
Keuntungan memakai custom error:
Memudahkan debugging
Anda tahu persis jenis error yang muncul.Bisa membuat kategori error
Misalnya:- ValidationError
- AuthenticationError
- DatabaseError
- NetworkError
Profesional dan siap production
Aplikasi besar seperti React, Vue, Node.js semuanya memakai custom error.
Praktik Terbaik dalam Pembuatan Custom Error
Untuk menjaga kualitas codebase, berikut best practice yang dianjurkan:
1. Selalu gunakan kelas turunan dari Error
Bukan string atau object biasa.
class AppError extends Error {}Code language: JavaScript (javascript)
2. Tambahkan properti tambahan jika perlu
Misalnya statusCode untuk API.
class APIError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.name = "APIError";
}
}Code language: JavaScript (javascript)
3. Gunakan nama error yang konsisten
Nama format yang umum:
- ValidationError
- AuthError
- NotFoundError
4. Jangan gunakan custom error untuk hal kecil
Misal:
❌ Tidak perlu membuat error khusus hanya untuk mengecek angka negatif.
Custom error perlu dipakai untuk kondisi besar dan penting.
5. Selalu sertakan pesan error yang jelas
Contoh buruk:
throw new Error("Error");Code language: JavaScript (javascript)
Contoh baik:
throw new Error("Username tidak boleh kosong");Code language: JavaScript (javascript)
6. Jangan lupa panggil super(message)
Jika tidak, properti message tidak akan terbentuk dengan benar.
7. Gunakan instanceof untuk identifikasi
Ini cara terbaik memisahkan jenis error.
if (error instanceof ValidationError) {
// handle validasi
}Code language: JavaScript (javascript)
Error Handling pada Fungsi dan Modular Code
Dalam aplikasi JavaScript modern yang sudah modular dan terdiri dari banyak fungsi, tantangan utama adalah menempatkan error handling pada lokasi yang tepat. Kesalahan menaruh try…catch dapat menyebabkan kode berantakan, error tidak muncul, atau malah menimbulkan silent bug yang sulit dideteksi.
Bagian ini membahas bagaimana menangani error di level fungsi, modul, dan level global.
Menempatkan Error Handling di Level yang Tepat
Kesalahan terbesar pemula adalah:
- Meletakkan
try…catchterlalu banyak - Meletakkan
try…catchterlalu dekat ke setiap baris kode - Meletakkan error handling di lokasi yang tidak strategis
- Atau sebaliknya: tidak memasang error handling sama sekali
Prinsip utama:
- Letakkan error handling sedekat mungkin dengan logika bisnis yang Anda ingin lindungi.
Contoh yang Salah (Terlalu banyak try/catch)
function prosesData(data) {
try {
let x = data.x;
} catch (e) {}
try {
let y = data.y;
} catch (e) {}
try {
return x + y;
} catch (e) {}
}Code language: JavaScript (javascript)
Ini membuat debugging menjadi mimpi buruk, karena error “ditelan” di setiap tahap.
Contoh yang Benar (Satu try/catch untuk satu unit logika)
function prosesData(data) {
try {
const { x, y } = data;
return x + y;
} catch (error) {
console.error("Gagal memproses data:", error.message);
return null;
}
}Code language: JavaScript (javascript)
Best practice penentuan lokasi try/catch:
- Taruh di batas unit of work (fungsi, handler event, atau modul).
- Jangan gunakan
try…catchuntuk validasi kecil—gunakanif. - Gunakan
try…catchhanya untuk kode yang berpotensi melempar error. - Hindari menangkap error terlalu awal; biarkan naik jika perlu.
Menangkap Error di Dalam Fungsi
Fungsi adalah tempat paling strategis untuk menangkap error tertentu. Misal:
- Validasi input
- Panggilan API internal
- Konversi data
- Proses kalkulasi penting
Contoh:
function parseUser(jsonText) {
try {
const user = JSON.parse(jsonText);
return user;
} catch (error) {
throw new Error("Format JSON tidak valid");
}
}Code language: JavaScript (javascript)
Di sini fungsi parseUser memutuskan:
- Error JSON asli tidak diteruskan apa adanya
- Error dikonversi menjadi pesan yang lebih jelas
- Error dilempar lagi ke level atas
Kapan menangkap error di dalam fungsi?
Gunakan teknik ini jika:
- Fungsi perlu memberi error yang lebih spesifik
- Anda ingin membungkus error eksternal menjadi error internal
- Anda ingin memastikan fungsi tetap pure atau rapi
- Fungsi dijalankan berkali-kali dan Anda ingin pesan konsisten
Meneruskan Error ke Atas (Error Propagation)
Terkadang, sebuah fungsi tidak boleh menangani error di dalamnya.
Biarkan error naik ke fungsi pemanggil (throw upward) agar dapat ditangani di level lebih tinggi.
Contoh:
function hitungTotal(items) {
if (!Array.isArray(items)) {
throw new Error("items harus berupa array");
}
return items.reduce((a, b) => a + b);
}
function main() {
try {
const total = hitungTotal("bukan array");
console.log("Total:", total);
} catch (error) {
console.error("Terjadi kesalahan:", error.message);
}
}
main();Code language: JavaScript (javascript)
Di sini:
hitungTotal()tidak menangkap error (SENGAJA)- Errornya diteruskan ke
main() main()yang menangani error secara global di proses itu
Kapan Anda harus melakukan error propagation?
- Fungsi adalah bagian dari sistem yang lebih besar
- Anda ingin error ditangani di suatu lapisan (misal “controller”, bukan “service”)
- Modul kecil tidak perlu tahu cara menangani error
- Menggunakan arsitektur seperti MVC, Clean Architecture, atau modul API
Error Handling Global (window.onerror / process.on)
Selain menangani error di level fungsi dan modul, JavaScript menyediakan error handler global untuk menangkap error yang tidak tertangkap (uncaught errors).
1. Global Error Handling di Browser
Browser menyediakan:
window.onerror
window.onerror = function (message, source, lineno, colno, error) {
console.log("Global Error:", message);
console.log("Lokasi:", source + ":" + lineno);
console.log("Detail:", error);
};Code language: JavaScript (javascript)
Fungsi ini menangkap:
- Error runtime yang tidak di-catch
- Error syntax (kadang)
- Error dari event handler
window.addEventListener("unhandledrejection")
Menangani Promise yang gagal tanpa .catch:
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled Promise:", event.reason);
});Code language: JavaScript (javascript)
2. Global Error Handling di Node.js
Node.js memberikan dua event khusus:
process.on("uncaughtException")
Menangkap error synchronous yang tidak tertangkap.
process.on("uncaughtException", (error) => {
console.error("Uncaught Exception:", error);
// idealnya lakukan restart server
});Code language: JavaScript (javascript)
process.on("unhandledRejection")
Untuk Promise tanpa .catch:
process.on("unhandledRejection", (reason) => {
console.error("Unhandled Rejection:", reason);
});Code language: JavaScript (javascript)
Catatan Penting:
Menggunakan error handler global tidak menggantikan try/catch lokal, tetapi:
- Menjadi laporan terakhir sebelum aplikasi mati
- Berguna untuk logging server (Sentry, LogRocket, ELK)
- Tidak disarankan untuk recovery logika bisnis
- Lebih cocok untuk notifikasi dan debugging
Error Handling pada Asynchronous JavaScript
Asynchronous JavaScript menghadirkan tantangan tersendiri dalam error handling. Berbeda dengan kode sinkron yang mudah di-trace, error pada async code sering muncul terlambat, di luar blok eksekusi utama, atau tersembunyi dalam callback atau promise chain. Bagian ini membahas seluruh teknik modern untuk menangani error dalam kode asynchronous.
Tantangan Error Handling pada Async Code
Beberapa masalah umum dalam asynchronous JavaScript:
1. Error Tidak Terjadi di Tempat yang Sama dengan Kode Pemanggil
Contoh: callback dipanggil beberapa detik kemudian, sehingga try/catch awal tidak mempengaruhi error yang terjadi.
2. Callback Hell Memperburuk Trace Error
Semakin dalam callback bersarang, semakin sulit membaca alur kesalahan.
3. Promise Membutuhkan Catch Tersendiri
Error hanya tertangkap jika chain memiliki .catch().
4. Async/Await Butuh try/catch di Tiap Level
Jika tidak menggunakan try/catch, error dilempar sebagai rejected promise.
5. Silent Error
Misalnya, Promise yang tidak ditangkap akan menimbulkan “UnhandledPromiseRejection”.
Penanganan Error pada Callback
Callback menggunakan pola error-first:
function getData(callback) {
setTimeout(() => {
const error = Math.random() > 0.5 ? "Gagal ambil data" : null
if (error) return callback(error)
callback(null, { name: "John" })
}, 1000)
}
getData((err, data) => {
if (err) {
console.error("Error:", err)
return
}
console.log("Data:", data)
})Code language: JavaScript (javascript)
Ciri khas pola ini:
- Parameter pertama = error
- Callback harus selalu memeriksa error
- Rawat error sedini mungkin untuk menghindari callback hell
Penanganan Error pada Promise (catch)
Error pada promise tertangkap menggunakan .catch().
Contoh:
const getUser = () => {
return new Promise((resolve, reject) => {
reject("User tidak ditemukan")
})
}
getUser()
.then(user => console.log(user))
.catch(err => console.error("Error:", err))Code language: JavaScript (javascript)
Behavior penting:
- Error dalam
thenotomatis masuk kecatch
Promise.resolve(10)
.then(() => {
throw "Oops"
})
.catch(err => console.log("Tertangkap:", err))Code language: JavaScript (javascript)
Promise.all dan Error yang Menghentikan Semua
Promise.all() akan langsung reject jika salah satu promise gagal.
Promise.all([
Promise.resolve("A"),
Promise.reject("Error pada B"),
Promise.resolve("C")
])
.then(result => console.log(result))
.catch(err => console.error("Error:", err))Code language: JavaScript (javascript)
Output:
Error: Error pada BCode language: JavaScript (javascript)
Solusi: Gunakan Promise.allSettled() jika ingin menangkap semua hasil, termasuk error.
Promise.allSettled([
Promise.resolve("A"),
Promise.reject("Error B"),
Promise.resolve("C")
]).then(console.log)Code language: JavaScript (javascript)
Output:
[
{ status: "fulfilled", value: "A" },
{ status: "rejected", reason: "Error B" },
{ status: "fulfilled", value: "C" }
]Code language: JavaScript (javascript)
Ini sangat berguna untuk tasks yang independen.
Error Handling pada Async/Await dengan try/catch
Async/await membuat penulisan lebih rapi, tetapi error harus ditangani dengan try/catch:
async function getData() {
try {
const result = await fetch("https://api.example.com/data")
return await result.json()
} catch (err) {
console.error("Terjadi error:", err)
}
}Code language: JavaScript (javascript)
Error di dalam async function → rejected promise
Jika function async tidak punya try/catch:
async function test() {
throw "Oops"
}Code language: JavaScript (javascript)
test() menghasilkan rejected promise.
Contoh Kasus API Fetch (Async/Await)
Contoh lengkap:
async function getUser() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1")
if (!response.ok) {
throw new Error("HTTP Error, status: " + response.status)
}
const data = await response.json()
console.log("User:", data)
} catch (err) {
console.error("Gagal mengambil user:", err.message)
}
}
getUser()Code language: JavaScript (javascript)
Error yang dapat terjadi:
- Jaringan mati
- Server down
- Response tidak valid JSON
- Status HTTP 4xx/5xx
- Timeout (butuh AbortController)
Kesalahan Umum yang Perlu Dihindari
Tidak memberi
.catch()pada promise
Dapat menyebabkan error global “UnhandledPromiseRejection”.Menggunakan try/catch pada kode async callback
Try/catch tidak bekerja pada kode async yang tidak di-await.Tidak memvalidasi response HTTP
fetch()tidak melempar error untuk status 404/500.Mengabaikan return dalam async
Menghasilkan promise yang tidak pernah resolve.Menggabungkan callback + promise tanpa alasan
Berpotensi membuat “callback-promise hell”.Tidak menempatkan error handling pada level yang tepat
Harus ada error handling:- di tiap async function
- di level global
- di level UI (user feedback)
Debugging Error di JavaScript
Debugging adalah proses menemukan sumber masalah dalam kode. Dalam JavaScript, kemampuan debugging yang baik akan mempercepat penyelesaian error, meningkatkan kualitas aplikasi, dan mengurangi risiko bug berulang. Bagian ini membahas teknik dasar debugging modern, mulai dari membaca stack trace hingga mengoptimalkan penggunaan DevTools.
Membaca Stack Trace dengan Benar
Stack trace adalah daftar urutan fungsi yang dipanggil sebelum error terjadi. Ini sangat penting untuk menemukan lokasi sebenarnya dari error.
Contoh error:
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
at getUserName (script.js:15)
at main (script.js:28)
at script.js:32Code language: JavaScript (javascript)
Cara membacanya:
Baris pertama: jenis error
TypeError: Cannot read properties of undefined
Baris berikutnya: lokasi fungsi penyebab error
at getUserName (script.js:15)
Ini adalah sumber error utama yang harus dicek dulu.
Fungsi di atasnya: siapa yang memanggil fungsi error
at main (script.js:28)
Baris terakhir: titik awal pemanggilan
script.js:32 adalah eksekusi awal yang memanggil main()
Console.log, Console.error, Console.warn
Console sangat membantu dalam debugging.
1. console.log()
Digunakan untuk melihat nilai variabel atau proses.
console.log("User:", user)Code language: JavaScript (javascript)
2. console.error()
Menampilkan error dengan styling merah → mudah terlihat.
console.error("Gagal load:", err)Code language: JavaScript (javascript)
3. console.warn()
Untuk menampilkan peringatan.
console.warn("Data tidak lengkap")Code language: JavaScript (javascript)
Tambahan penting:
console.table()→ menampilkan array/object dalam bentuk tabel.console.time()danconsole.timeEnd()→ memeriksa performa.console.group()→ mengelompokkan log agar rapi.
Menggunakan Debugger (Chrome DevTools)
DevTools memiliki fitur debugger yang menghentikan eksekusi kode secara otomatis.
Cara 1 — Menulis keyword debugger di kode:
function calculate() {
debugger
let x = 10
let y = 20
return x + y
}Code language: JavaScript (javascript)
Saat halaman dijalankan, DevTools akan berhenti di baris debugger.
Cara 2 — Membuka Sources Tab di Chrome:
- Buka DevTools → tab Sources
- Cari file JavaScript
- Klik nomor baris untuk membuat breakpoint
- Reload halaman
- Eksekusi akan berhenti tepat di baris tersebut
Keuntungan:
- Melihat nilai variabel secara real-time
- Mengontrol alur program
- Melihat call stack dengan jelas
- Bisa mengubah nilai variabel pada saat pause
Breakpoints, Step Over, Step Into
Breakpoints
Titik berhenti eksekusi kode. Digunakan untuk memeriksa keadaan aplikasi sebelum error.
Jenis breakpoints:
- Line Breakpoint — berhenti pada baris tertentu
- Conditional Breakpoint — berhenti hanya jika kondisi terpenuhi
Contoh: klik kanan nomor baris → “Add conditional breakpoint”
Kondisi: user.id === 5
Step Over (F10)
Menjalankan baris kode tanpa masuk ke fungsi yang dipanggil.
Cocok untuk:
- Menghindari fungsi besar yang tidak relevan
Step Into (F11)
Masuk ke dalam fungsi yang dipanggil pada baris tersebut.
Cocok untuk:
- Menelusuri error di fungsi internal
Step Out (Shift + F11)
Keluar dari fungsi saat ini dan kembali ke pemanggilnya.
Kapan digunakan:
- Jika Anda masuk terlalu dalam dan ingin kembali ke alur utama
Tips Debugging untuk Pemula
1. Jangan langsung memperbaiki error—baca errornya dulu
Error JavaScript biasanya memberikan petunjuk lengkap:
- Jenis error
- Baris
- File
- Stack trace
2. Reproduksi error secara konsisten
Error yang bisa diulang → lebih mudah diperbaiki.
3. Gunakan console.log() secara strategis
Debugging bukan spam log:
- Log input fungsi
- Log output fungsi
- Log nilai yang mencurigakan
4. Periksa apakah error disebabkan data kosong
80% error terjadi karena:
nullundefinedNaNstringkosongarraykosong
5. Isolasi bug
Pindahkan bagian kode ke area terpisah untuk mengetahui apakah error datang dari:
- logika function
- data
- state UI
6. Gunakan “Pretty Print” untuk file minified
Jika error berasal dari file .min.js, klik tombol { } di DevTools.
7. Gunakan breakpoints daripada spam console.log
Breakpoints memberikan:
- Nilai live variable
- Arah alur eksekusi
- Call stack penuh
8. Cek environment
Kadang error muncul karena:
- Cache browser
- Response API tidak sesuai
- Perbedaan Node.js version
9. Coba jalankan di environment lain
Jika error hanya muncul di satu browser:
- Cek compatibility
- Cek polyfill
10. Periksa dokumentasi fungsi/library
Kadang error muncul karena salah format data atau aturan library.
Custom Error di JavaScript
Selain error bawaan JavaScript seperti TypeError, ReferenceError, dan RangeError, aplikasi modern sering membutuhkan custom error. Custom error memungkinkan developer:
- Memberikan pesan error yang lebih spesifik
- Menandai jenis error dengan jelas
- Menangani error berbeda dengan cara berbeda di aplikasi besar
Kenapa Membuat Custom Error
Alasan membuat custom error:
Klasifikasi error lebih jelas
Misal membedakan error validasi dari error server.Memudahkan debugging
Memudahkan tim untuk memahami error tanpa membaca message panjang.Mendukung arsitektur modular
Setiap modul dapat melempar jenis error spesifik.Memberikan info tambahan
Misal kode status HTTP, ID transaksi, atau level error.
Membuat Class Error Sendiri
Cara membuat custom error:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}Code language: JavaScript (javascript)
Penjelasan:
extends Error→ mewarisi properti error standarsuper(message)→ memastikan message error tersimpanthis.name→ menandai jenis error
Menyimpan Informasi Tambahan
Custom error bisa menyimpan data tambahan untuk membantu debugging atau reporting:
class APIError extends Error {
constructor(message, statusCode, endpoint) {
super(message);
this.name = "APIError";
this.statusCode = statusCode;
this.endpoint = endpoint;
}
}
const error = new APIError("Tidak dapat mengambil data", 500, "/users");
console.log(error.statusCode); // 500
console.log(error.endpoint); // /usersCode language: JavaScript (javascript)
Menangani Custom Error di Aplikasi Besar
Di aplikasi besar, penting untuk menangkap dan memproses custom error secara berbeda.
Contoh:
try {
throw new ValidationError("Nama wajib diisi");
} catch (err) {
if (err instanceof ValidationError) {
console.warn("Validasi gagal:", err.message);
} else if (err instanceof APIError) {
console.error("API Error:", err.message, err.statusCode);
} else {
console.error("Error lain:", err.message);
}
}Code language: JavaScript (javascript)
Keuntungan:
- Pesan error lebih spesifik untuk user dan developer
- Bisa memisahkan error log antara validasi, server, atau runtime
Contoh Penggunaan Custom Error dalam Validasi Input
Praktik umum custom error: validasi input form.
class InputError extends Error {
constructor(field, message) {
super(message);
this.name = "InputError";
this.field = field;
}
}
function validateUser(user) {
if (!user.name) {
throw new InputError("name", "Nama tidak boleh kosong");
}
if (!user.email.includes("@")) {
throw new InputError("email", "Email tidak valid");
}
return true;
}
try {
validateUser({ name: "", email: "arisexample.com" });
} catch (err) {
if (err instanceof InputError) {
console.error(`Error pada field ${err.field}: ${err.message}`);
}
}Code language: JavaScript (javascript)
Output:
Error pada field name: Nama tidak boleh kosongCode language: JavaScript (javascript)
Manfaat:
- Mudah mengaitkan error dengan field input
- Memberikan pesan yang jelas ke UI
- Memudahkan logging error di backend
Kesimpulan
Error handling di JavaScript adalah bagian penting untuk menulis kode yang aman, stabil, dan mudah dipelihara. Dengan memahami try…catch…finally, throw, serta custom error, developer dapat menangani berbagai jenis error, mulai dari syntax, runtime, hingga logical error, baik pada kode sinkron maupun asynchronous. Selain itu, penerapan error handling yang tepat memudahkan debugging, meminimalkan crash aplikasi, dan memberikan pengalaman pengguna yang lebih baik.
Setelah menguasai dasar-dasar ini, langkah selanjutnya adalah mengeksplorasi topik lanjutan seperti Promise, async/await, Fetch API, dan Observables. Memahami alur error pada asynchronous code dan teknik modern dalam menangani error akan membuat aplikasi web lebih robust, modular, dan siap untuk pengembangan skala besar.