Panduan Definitif untuk Menangani Kesalahan dalam JavaScript
Diterbitkan: 2022-01-24Hukum Murphy menyatakan bahwa apa pun yang bisa salah pada akhirnya akan salah. Ini berlaku sedikit terlalu baik di dunia pemrograman. Jika Anda membuat aplikasi, kemungkinan besar Anda akan membuat bug dan masalah lainnya. Kesalahan dalam JavaScript adalah salah satu masalah umum seperti itu!
Keberhasilan produk perangkat lunak bergantung pada seberapa baik pembuatnya dapat mengatasi masalah ini sebelum merugikan penggunanya. Dan JavaScript, dari semua bahasa pemrograman, terkenal dengan desain penanganan kesalahan rata-rata.
Jika Anda sedang membangun aplikasi JavaScript, ada kemungkinan besar Anda akan mengacaukan tipe data di satu titik atau lainnya. Jika bukan itu, maka Anda mungkin akan mengganti undefined dengan operator null atau triple equals ( ===
) dengan operator double equals ( ==
).
Itu hanya manusia untuk membuat kesalahan. Inilah sebabnya kami akan menunjukkan kepada Anda semua yang perlu Anda ketahui tentang penanganan kesalahan dalam JavaScript.
Artikel ini akan memandu Anda melalui kesalahan dasar dalam JavaScript dan menjelaskan berbagai kesalahan yang mungkin Anda temui. Anda kemudian akan belajar cara mengidentifikasi dan memperbaiki kesalahan ini. Ada juga beberapa tip untuk menangani kesalahan secara efektif di lingkungan produksi.
Tanpa basa-basi lagi, mari kita mulai!
Apa Itu Kesalahan JavaScript?
Kesalahan dalam pemrograman mengacu pada situasi yang tidak memungkinkan program berfungsi secara normal. Itu bisa terjadi ketika sebuah program tidak tahu bagaimana menangani pekerjaan yang ada, seperti ketika mencoba membuka file yang tidak ada atau menjangkau titik akhir API berbasis web saat tidak ada konektivitas jaringan.
Situasi ini mendorong program untuk memberikan kesalahan kepada pengguna, menyatakan bahwa ia tidak tahu bagaimana melanjutkan. Program mengumpulkan informasi sebanyak mungkin tentang kesalahan dan kemudian melaporkan bahwa ia tidak dapat melanjutkan.
Pemrogram cerdas mencoba memprediksi dan menutupi skenario ini sehingga pengguna tidak perlu menemukan pesan kesalahan teknis seperti "404" secara mandiri. Sebaliknya, mereka menunjukkan pesan yang jauh lebih mudah dipahami: "Halaman tidak dapat ditemukan."
Kesalahan dalam JavaScript adalah objek yang ditampilkan setiap kali kesalahan pemrograman terjadi. Objek ini berisi banyak informasi tentang jenis kesalahan, pernyataan yang menyebabkan kesalahan, dan pelacakan tumpukan saat kesalahan terjadi. JavaScript juga memungkinkan pemrogram untuk membuat kesalahan khusus untuk memberikan informasi tambahan saat men-debug masalah.
Properti dari Kesalahan
Sekarang definisi kesalahan JavaScript jelas, saatnya untuk menyelami detailnya.
Kesalahan dalam JavaScript membawa properti standar dan khusus tertentu yang membantu memahami penyebab dan efek kesalahan. Secara default, kesalahan dalam JavaScript berisi tiga properti:
- pesan : Nilai string yang membawa pesan kesalahan
- name : Jenis kesalahan yang terjadi (Kami akan membahasnya lebih dalam di bagian selanjutnya)
- stack : Jejak tumpukan kode yang dieksekusi saat kesalahan terjadi.
Selain itu, kesalahan juga dapat membawa properti seperti columnNumber, lineNumber, fileName, dll., untuk menjelaskan kesalahan dengan lebih baik. Namun, properti ini tidak standar dan mungkin ada atau tidak ada di setiap objek kesalahan yang dihasilkan dari aplikasi JavaScript Anda.
Memahami Jejak Tumpukan
Jejak tumpukan adalah daftar metode pemanggilan program saat peristiwa seperti pengecualian atau peringatan terjadi. Seperti inilah contoh jejak tumpukan disertai dengan pengecualian:

Seperti yang Anda lihat, itu dimulai dengan mencetak nama dan pesan kesalahan, diikuti dengan daftar metode yang dipanggil. Setiap pemanggilan metode menyatakan lokasi kode sumbernya dan baris di mana ia dipanggil. Anda dapat menggunakan data ini untuk menavigasi basis kode Anda dan mengidentifikasi bagian kode mana yang menyebabkan kesalahan.
Daftar metode ini disusun secara bertumpuk. Ini menunjukkan di mana pengecualian Anda pertama kali dilemparkan dan bagaimana itu disebarkan melalui panggilan metode bertumpuk. Menerapkan tangkapan untuk pengecualian tidak akan membiarkannya menyebar melalui tumpukan dan merusak program Anda. Namun, Anda mungkin ingin membiarkan kesalahan fatal tidak tertangkap untuk membuat program crash dalam beberapa skenario dengan sengaja.
Kesalahan vs Pengecualian
Kebanyakan orang biasanya menganggap kesalahan dan pengecualian sebagai hal yang sama. Namun, penting untuk mencatat sedikit perbedaan mendasar di antara mereka.
Untuk memahami ini lebih baik, mari kita ambil contoh singkat. Inilah cara Anda mendefinisikan kesalahan dalam JavaScript:
const wrongTypeError = TypeError("Wrong type found, expected character")
Dan beginilah objek yang wrongTypeError
menjadi pengecualian:
throw wrongTypeError
Namun, kebanyakan orang cenderung menggunakan bentuk singkatan yang mendefinisikan objek kesalahan saat melemparnya:
throw TypeError("Wrong type found, expected character")
Ini adalah praktik standar. Namun, itu salah satu alasan mengapa pengembang cenderung mencampuradukkan pengecualian dan kesalahan. Oleh karena itu, mengetahui dasar-dasarnya sangat penting meskipun Anda menggunakan steno untuk menyelesaikan pekerjaan Anda dengan cepat.
Jenis Kesalahan dalam JavaScript
Ada berbagai jenis kesalahan yang telah ditentukan sebelumnya dalam JavaScript. Mereka secara otomatis dipilih dan ditentukan oleh runtime JavaScript setiap kali programmer tidak secara eksplisit menangani kesalahan dalam aplikasi.
Bagian ini akan memandu Anda melalui beberapa jenis kesalahan yang paling umum dalam JavaScript dan memahami kapan dan mengapa itu terjadi.
RentangError
RangeError dilempar ketika variabel diatur dengan nilai di luar rentang nilai legalnya. Biasanya terjadi ketika meneruskan nilai sebagai argumen ke suatu fungsi, dan nilai yang diberikan tidak terletak pada kisaran parameter fungsi. Kadang-kadang bisa menjadi sulit untuk diperbaiki saat menggunakan perpustakaan pihak ketiga yang didokumentasikan dengan buruk karena Anda perlu mengetahui kisaran nilai yang mungkin agar argumen dapat meneruskan nilai yang benar.
Beberapa skenario umum di mana RangeError terjadi adalah:
- Mencoba membuat larik dengan panjang ilegal melalui konstruktor Array.
- Melewati nilai buruk ke metode numerik seperti
toExponential()
,toPrecision()
,toFixed()
, dll. - Melewati nilai ilegal ke fungsi string seperti
normalize()
.
ReferensiError
ReferenceError terjadi ketika ada yang salah dengan referensi variabel dalam kode Anda. Anda mungkin lupa menentukan nilai untuk variabel sebelum menggunakannya, atau Anda mungkin mencoba menggunakan variabel yang tidak dapat diakses dalam kode Anda. Bagaimanapun, menelusuri jejak tumpukan memberikan banyak informasi untuk menemukan dan memperbaiki referensi variabel yang salah.
Beberapa alasan umum mengapa ReferenceErrors terjadi adalah:
- Membuat kesalahan ketik pada nama variabel.
- Mencoba mengakses variabel cakupan blok di luar cakupannya.
- Merujuk variabel global dari perpustakaan eksternal (seperti $ dari jQuery) sebelum dimuat.
Kesalahan sintaks
Kesalahan ini adalah salah satu yang paling sederhana untuk diperbaiki karena menunjukkan kesalahan dalam sintaks kode. Karena JavaScript adalah bahasa skrip yang ditafsirkan dan bukan dikompilasi, ini dibuang saat aplikasi mengeksekusi skrip yang berisi kesalahan. Dalam kasus bahasa yang dikompilasi, kesalahan tersebut diidentifikasi selama kompilasi. Dengan demikian, binari aplikasi tidak dibuat sampai ini diperbaiki.
Beberapa alasan umum mengapa SyntaxErrors mungkin terjadi adalah:
- Koma terbalik hilang
- Tanda kurung penutup hilang
- Penjajaran kurung kurawal atau karakter lain yang tidak tepat
Ini adalah praktik yang baik untuk menggunakan alat linting di IDE Anda untuk mengidentifikasi kesalahan tersebut untuk Anda sebelum mereka mencapai browser.
TypeError
TypeError adalah salah satu kesalahan paling umum dalam aplikasi JavaScript. Kesalahan ini dibuat ketika beberapa nilai tidak berubah menjadi tipe tertentu yang diharapkan. Beberapa kasus umum ketika itu terjadi adalah:
- Memanggil objek yang bukan metode.
- Mencoba mengakses properti objek null atau tidak terdefinisi
- Memperlakukan string sebagai angka atau sebaliknya
Ada lebih banyak kemungkinan di mana TypeError dapat terjadi. Kita akan melihat beberapa contoh terkenal nanti dan mempelajari cara memperbaikinya.
Kesalahan internal
Jenis InternalError digunakan ketika pengecualian terjadi di mesin runtime JavaScript. Ini mungkin atau mungkin tidak menunjukkan masalah dengan kode Anda.
Lebih sering daripada tidak, InternalError hanya terjadi dalam dua skenario:
- Saat tambalan atau pembaruan ke runtime JavaScript membawa bug yang menimbulkan pengecualian (ini sangat jarang terjadi)
- Ketika kode Anda berisi entitas yang terlalu besar untuk mesin JavaScript (misalnya terlalu banyak kasus sakelar, inisialisasi array terlalu besar, terlalu banyak rekursi)
Pendekatan yang paling tepat untuk mengatasi kesalahan ini adalah mengidentifikasi penyebabnya melalui pesan kesalahan dan menyusun ulang logika aplikasi Anda, jika memungkinkan, untuk menghilangkan lonjakan beban kerja yang tiba-tiba pada mesin JavaScript.
kesalahan URI
URIError terjadi ketika fungsi penanganan URI global seperti decodeURIComponent
digunakan secara ilegal. Ini biasanya menunjukkan bahwa parameter yang diteruskan ke pemanggilan metode tidak sesuai dengan standar URI dan dengan demikian tidak diuraikan oleh metode dengan benar.
Mendiagnosis kesalahan ini biasanya mudah karena Anda hanya perlu memeriksa argumen untuk malformasi.
kesalahan evaluasi
EvalError terjadi saat terjadi kesalahan dengan pemanggilan fungsi eval()
. Fungsi eval()
digunakan untuk mengeksekusi kode JavaScript yang disimpan dalam string. Namun, karena menggunakan fungsi eval()
sangat tidak disarankan karena masalah keamanan dan spesifikasi ECMAScript saat ini tidak membuang kelas EvalError
lagi, jenis kesalahan ini ada hanya untuk mempertahankan kompatibilitas mundur dengan kode JavaScript lawas.
Jika Anda sedang mengerjakan JavaScript versi lama, Anda mungkin mengalami kesalahan ini. Bagaimanapun, yang terbaik adalah menyelidiki kode yang dieksekusi dalam panggilan fungsi eval()
untuk pengecualian apa pun.
Membuat Jenis Kesalahan Kustom
Meskipun JavaScript menawarkan daftar kelas jenis kesalahan yang memadai untuk menutupi sebagian besar skenario, Anda selalu dapat membuat jenis kesalahan baru jika daftar tidak memenuhi persyaratan Anda. Fondasi dari fleksibilitas ini terletak pada kenyataan bahwa JavaScript memungkinkan Anda untuk melempar sesuatu secara harfiah dengan perintah throw
.
Jadi, secara teknis, pernyataan ini sepenuhnya sah:
throw 8 throw "An error occurred"
Namun, melempar tipe data primitif tidak memberikan detail tentang kesalahan, seperti jenisnya, nama, atau pelacakan tumpukan yang menyertainya. Untuk memperbaikinya dan menstandardisasi proses penanganan kesalahan, kelas Error
telah disediakan. Juga tidak disarankan untuk menggunakan tipe data primitif saat melempar pengecualian.
Anda dapat memperluas kelas Error
untuk membuat kelas kesalahan khusus Anda. Berikut adalah contoh dasar bagaimana Anda dapat melakukan ini:
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }
Dan Anda dapat menggunakannya dengan cara berikut:
throw ValidationError("Property not found: name")
Dan Anda kemudian dapat mengidentifikasinya menggunakan kata kunci instanceof
:
try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }
10 Kesalahan Paling Umum di JavaScript
Sekarang setelah Anda memahami jenis kesalahan umum dan cara membuat kesalahan khusus, inilah saatnya untuk melihat beberapa kesalahan paling umum yang akan Anda hadapi saat menulis kode JavaScript.
1. RangeError Tidak Tertangkap
Kesalahan ini terjadi di Google Chrome dalam beberapa skenario. Pertama, itu bisa terjadi jika Anda memanggil fungsi rekursif dan tidak berhenti. Anda dapat memeriksanya sendiri di Konsol Pengembang Chrome:

Jadi untuk mengatasi kesalahan seperti itu, pastikan untuk mendefinisikan kasus perbatasan dari fungsi rekursif Anda dengan benar. Alasan lain mengapa kesalahan ini terjadi adalah jika Anda telah melewati nilai yang berada di luar rentang parameter fungsi. Berikut ini contohnya:

Pesan kesalahan biasanya akan menunjukkan apa yang salah dengan kode Anda. Setelah Anda membuat perubahan, itu akan diselesaikan.

2. TypeError Tidak Tertangkap: Tidak dapat mengatur properti
Kesalahan ini terjadi saat Anda menyetel properti pada referensi yang tidak ditentukan. Anda dapat mereproduksi masalah dengan kode ini:
var list list.count = 0
Inilah output yang akan Anda terima:

Untuk memperbaiki kesalahan ini, inisialisasi referensi dengan nilai sebelum mengakses propertinya. Begini tampilannya saat diperbaiki:

3. TypeError Tidak Tertangkap: Tidak dapat membaca properti
Ini adalah salah satu kesalahan yang paling sering terjadi dalam JavaScript. Kesalahan ini terjadi saat Anda mencoba membaca properti atau memanggil fungsi pada objek yang tidak ditentukan. Anda dapat mereproduksinya dengan sangat mudah dengan menjalankan kode berikut di konsol Pengembang Chrome:
var func func.call()
Berikut outputnya:

Objek yang tidak ditentukan adalah salah satu dari banyak kemungkinan penyebab kesalahan ini. Penyebab menonjol lainnya dari masalah ini adalah inisialisasi status yang tidak tepat saat merender UI. Berikut adalah contoh dunia nyata dari aplikasi React:
import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;
Aplikasi dimulai dengan wadah status kosong dan dilengkapi dengan beberapa item setelah penundaan 2 detik. Penundaan dilakukan untuk meniru panggilan jaringan. Bahkan jika jaringan Anda super cepat, Anda masih akan menghadapi penundaan kecil karena komponen akan dirender setidaknya sekali. Jika Anda mencoba menjalankan aplikasi ini, Anda akan menerima kesalahan berikut:

Ini karena, pada saat rendering, wadah status tidak ditentukan; dengan demikian, tidak ada items
properti di atasnya. Memperbaiki kesalahan ini mudah. Anda hanya perlu memberikan nilai default awal ke penampung status.
// ... const [state, setState] = useState({items: []}); // ...
Sekarang, setelah penundaan yang ditetapkan, aplikasi Anda akan menampilkan output yang serupa:

Perbaikan yang tepat dalam kode Anda mungkin berbeda, tetapi intinya di sini adalah untuk selalu menginisialisasi variabel Anda dengan benar sebelum menggunakannya.
4. TypeError: 'undefined' bukan objek
Kesalahan ini terjadi di Safari saat Anda mencoba mengakses properti atau memanggil metode pada objek yang tidak ditentukan. Anda dapat menjalankan kode yang sama dari atas untuk mereproduksi kesalahan sendiri.

Solusi untuk kesalahan ini juga sama — pastikan Anda telah menginisialisasi variabel dengan benar dan variabel tersebut tidak terdefinisi saat properti atau metode diakses.
5. TypeError: null bukan objek
Ini, sekali lagi, mirip dengan kesalahan sebelumnya. Itu terjadi di Safari, dan satu-satunya perbedaan antara kedua kesalahan itu adalah kesalahan ini dilempar ketika objek yang properti atau metodenya sedang diakses adalah null
alih-alih undefined
. Anda dapat mereproduksi ini dengan menjalankan potongan kode berikut:
var func = null func.call()
Inilah output yang akan Anda terima:

Karena null
adalah nilai yang secara eksplisit disetel ke variabel dan tidak ditetapkan secara otomatis oleh JavaScript. Kesalahan ini hanya dapat terjadi jika Anda mencoba mengakses variabel yang Anda setel null
sendiri. Jadi, Anda perlu meninjau kembali kode Anda dan memeriksa apakah logika yang Anda tulis benar atau tidak.
6. TypeError: Tidak dapat membaca properti 'panjang'
Kesalahan ini terjadi di Chrome saat Anda mencoba membaca panjang objek null
atau undefined
. Penyebab masalah ini mirip dengan masalah sebelumnya, tetapi cukup sering terjadi saat menangani daftar; oleh karena itu layak disebutkan secara khusus. Inilah cara Anda dapat mereproduksi masalah:

Namun, di versi Chrome yang lebih baru, kesalahan ini dilaporkan sebagai Uncaught TypeError: Cannot read properties of undefined
. Begini tampilannya sekarang:

Perbaikannya, sekali lagi, adalah memastikan bahwa objek yang panjangnya Anda coba akses ada dan tidak disetel ke null
.
7. TypeError: 'undefined' bukan fungsi
Kesalahan ini terjadi saat Anda mencoba memanggil metode yang tidak ada di skrip Anda, atau ada tetapi tidak bisa direferensikan dalam konteks pemanggilan. Kesalahan ini biasanya terjadi di Google Chrome, dan Anda dapat menyelesaikannya dengan memeriksa baris kode yang melempar kesalahan. Jika Anda menemukan kesalahan ketik, perbaiki dan periksa apakah itu menyelesaikan masalah Anda.
Jika Anda telah menggunakan kata kunci referensi diri this
dalam kode Anda, kesalahan ini mungkin muncul jika this
tidak terikat dengan tepat ke konteks Anda. Perhatikan kode berikut:
function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })
Jika Anda mengeksekusi kode di atas, itu akan membuang kesalahan yang kita bahas. Itu terjadi karena fungsi anonim yang diteruskan sebagai pendengar acara sedang dieksekusi dalam konteks document
.
Sebaliknya, fungsi showAlert
didefinisikan dalam konteks window
.
Untuk mengatasi ini, Anda harus meneruskan referensi yang tepat ke fungsi dengan mengikatnya dengan metode bind()
:
document.addEventListener("click", this.showAlert.bind(this))
8. ReferenceError: acara tidak ditentukan
Kesalahan ini terjadi saat Anda mencoba mengakses referensi yang tidak ditentukan dalam cakupan panggilan. Ini biasanya terjadi ketika menangani peristiwa karena mereka sering memberi Anda referensi yang disebut event
dalam fungsi panggilan balik. Kesalahan ini dapat terjadi jika Anda lupa mendefinisikan argumen peristiwa di parameter fungsi Anda atau salah mengejanya.
Kesalahan ini mungkin tidak terjadi di Internet Explorer atau Google Chrome (karena IE menawarkan variabel peristiwa global dan Chrome melampirkan variabel peristiwa secara otomatis ke handler), tetapi kesalahan ini dapat terjadi di Firefox. Jadi disarankan untuk mengawasi kesalahan kecil seperti itu.
9. TypeError: Penetapan ke variabel konstan
Ini adalah kesalahan yang muncul karena kecerobohan. Jika Anda mencoba menetapkan nilai baru ke variabel konstan, Anda akan mendapatkan hasil seperti itu:

Meskipun tampaknya mudah untuk diperbaiki sekarang, bayangkan ratusan deklarasi variabel seperti itu dan salah satunya salah didefinisikan sebagai const
alih-alih let
! Tidak seperti bahasa scripting lain seperti PHP, ada sedikit perbedaan antara gaya mendeklarasikan konstanta dan variabel dalam JavaScript. Oleh karena itu disarankan untuk memeriksa deklarasi Anda terlebih dahulu ketika Anda menghadapi kesalahan ini. Anda juga dapat mengalami kesalahan ini jika Anda lupa bahwa referensi tersebut adalah konstanta dan menggunakannya sebagai variabel. Ini menunjukkan kecerobohan atau kelemahan logika aplikasi Anda. Pastikan untuk memeriksa ini ketika mencoba memperbaiki masalah ini.
10. (tidak diketahui): Kesalahan skrip
Kesalahan skrip terjadi saat skrip pihak ketiga mengirimkan kesalahan ke browser Anda. Kesalahan ini diikuti oleh (tidak diketahui) karena skrip pihak ketiga milik domain yang berbeda dari aplikasi Anda. Peramban menyembunyikan detail lainnya untuk mencegah bocornya informasi sensitif dari skrip pihak ketiga.
Anda tidak dapat mengatasi kesalahan ini tanpa mengetahui detail lengkapnya. Inilah yang dapat Anda lakukan untuk mendapatkan informasi lebih lanjut tentang kesalahan:
- Tambahkan atribut
crossorigin
di tag skrip. - Setel tajuk
Access-Control-Allow-Origin
yang benar di server yang menghosting skrip. - [Opsional] Jika Anda tidak memiliki akses ke server yang menghosting skrip, Anda dapat mempertimbangkan untuk menggunakan proxy untuk menyampaikan permintaan Anda ke server dan kembali ke klien dengan header yang benar.
Setelah Anda dapat mengakses detail kesalahan, Anda kemudian dapat mengatur untuk memperbaiki masalah, yang mungkin akan terjadi dengan perpustakaan pihak ketiga atau jaringan.
Cara Mengidentifikasi dan Mencegah Kesalahan dalam JavaScript
Meskipun kesalahan yang dibahas di atas adalah yang paling umum dan sering terjadi di JavaScript, Anda akan menemukan, mengandalkan beberapa contoh tidak akan pernah cukup. Sangat penting untuk memahami cara mendeteksi dan mencegah segala jenis kesalahan dalam aplikasi JavaScript saat mengembangkannya. Berikut adalah bagaimana Anda dapat menangani kesalahan dalam JavaScript.
Kesalahan Lempar dan Tangkap Secara Manual
Cara paling mendasar untuk menangani kesalahan yang telah dilemparkan baik secara manual atau oleh runtime adalah dengan menangkapnya. Seperti kebanyakan bahasa lain, JavaScript menawarkan serangkaian kata kunci untuk menangani kesalahan. Sangat penting untuk mengetahui masing-masing secara mendalam sebelum Anda mulai menangani kesalahan di aplikasi JavaScript Anda.
melemparkan
Kata kunci pertama dan paling dasar dari himpunan adalah throw
. Sebagai bukti, kata kunci throw digunakan untuk melempar kesalahan untuk membuat pengecualian di runtime JavaScript secara manual. Kami telah membahas ini sebelumnya di bagian ini, dan inilah inti dari arti kata kunci ini:
- Anda dapat
throw
apa saja, termasuk angka, string, dan objekError
. - Namun, tidak disarankan untuk membuang tipe data primitif seperti string dan angka karena tidak membawa informasi debug tentang kesalahan.
- Contoh:
throw TypeError("Please provide a string")
mencoba
Kata kunci try
digunakan untuk menunjukkan bahwa sebuah blok kode mungkin mengeluarkan pengecualian. Sintaksnya adalah:
try { // error-prone code here }
Penting untuk dicatat bahwa blok catch
harus selalu mengikuti blok try
untuk menangani kesalahan secara efektif.
menangkap
Kata kunci catch
digunakan untuk membuat blok catch. Blok kode ini bertanggung jawab untuk menangani kesalahan yang ditangkap oleh blok try
tambahan. Berikut sintaksnya:
catch (exception) { // code to handle the exception here }
Dan beginilah cara Anda mengimplementasikan blok try
dan catch
bersama-sama:
try { // business logic code } catch (exception) { // error handling code }
Tidak seperti C++ atau Java, Anda tidak dapat menambahkan beberapa blok catch
ke blok try
di JavaScript. Ini berarti Anda tidak dapat melakukan ini:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }
Sebagai gantinya, Anda dapat menggunakan pernyataan if...else
atau pernyataan switch case di dalam blok catch tunggal untuk menangani semua kemungkinan kasus kesalahan. Ini akan terlihat seperti ini:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }
akhirnya
Kata kunci finally
digunakan untuk mendefinisikan blok kode yang dijalankan setelah kesalahan ditangani. Blok ini dieksekusi setelah blok try dan catch.
Juga, blok akhirnya akan dieksekusi terlepas dari hasil dari dua blok lainnya. Ini berarti bahwa bahkan jika blok catch tidak dapat menangani kesalahan sepenuhnya atau kesalahan dilemparkan ke blok catch, interpreter akan mengeksekusi kode di blok akhirnya sebelum program macet.
Agar dianggap valid, blok coba dalam JavaScript harus diikuti oleh blok tangkapan atau akhirnya. Tanpa semua itu, interpreter akan memunculkan SyntaxError. Oleh karena itu, pastikan untuk mengikuti blok percobaan Anda dengan setidaknya salah satu dari mereka saat menangani kesalahan.
Tangani Kesalahan Secara Global Dengan Metode onerror()
Metode onerror()
tersedia untuk semua elemen HTML untuk menangani kesalahan apa pun yang mungkin terjadi dengannya. Misalnya, jika tag img
tidak dapat menemukan gambar yang URL-nya ditentukan, tag akan mengaktifkan metode onerror untuk memungkinkan pengguna menangani kesalahan.
Biasanya, Anda akan memberikan URL gambar lain dalam panggilan onerror agar tag img
kembali. Ini adalah bagaimana Anda dapat melakukannya melalui JavaScript:
const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }
Namun, Anda dapat menggunakan fitur ini untuk membuat mekanisme penanganan kesalahan global untuk aplikasi Anda. Berikut cara melakukannya:
window.onerror = (event) => { console.log("Error occurred: " + event) }
Dengan event handler ini, Anda dapat menyingkirkan beberapa blok try...catch
yang ada di dalam kode Anda dan memusatkan penanganan error aplikasi Anda mirip dengan penanganan event. Anda dapat melampirkan beberapa penangan kesalahan ke jendela untuk mempertahankan Prinsip Tanggung Jawab Tunggal dari prinsip desain SOLID. Penerjemah akan menggilir semua penangan hingga mencapai yang sesuai.
Lewati Kesalahan melalui Panggilan Balik
Sementara fungsi sederhana dan linier memungkinkan penanganan kesalahan tetap sederhana, panggilan balik dapat memperumit urusan.
Perhatikan potongan kode berikut:
Butuh solusi hosting yang memberi Anda keunggulan kompetitif? Kinsta membantu Anda dengan kecepatan luar biasa, keamanan canggih, dan penskalaan otomatis. Lihat rencana kami
const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)
Fungsi di atas menunjukkan kondisi asinkron di mana suatu fungsi membutuhkan waktu untuk memproses operasi dan mengembalikan hasilnya nanti dengan bantuan panggilan balik.
Jika Anda mencoba memasukkan string alih-alih 4 dalam panggilan fungsi, Anda akan mendapatkan NaN
sebagai hasilnya.
Ini perlu ditangani dengan benar. Berikut caranya:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }
Ini harus menyelesaikan masalah secara ideal. Namun, jika Anda mencoba meneruskan string ke panggilan fungsi, Anda akan menerima ini:

Meskipun Anda telah menerapkan blok coba-tangkap saat memanggil fungsi, masih dikatakan kesalahannya tidak tertangkap. Kesalahan dilempar setelah blok tangkap dieksekusi karena penundaan waktu habis.
Ini dapat terjadi dengan cepat dalam panggilan jaringan, di mana penundaan tak terduga terjadi. Anda perlu menangani kasus seperti itu saat mengembangkan aplikasi Anda.
Inilah cara Anda dapat menangani kesalahan dengan benar dalam panggilan balik:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }
Sekarang, output di konsol akan menjadi:

Ini menunjukkan bahwa kesalahan telah ditangani dengan tepat.
Menangani Kesalahan dalam Janji
Kebanyakan orang cenderung lebih memilih janji untuk menangani aktivitas asinkron. Janji memiliki keuntungan lain — janji yang ditolak tidak menghentikan skrip Anda. Namun, Anda masih perlu menerapkan blok tangkap untuk menangani kesalahan dalam janji. Untuk memahami ini dengan lebih baik, mari kita tulis ulang fungsi calculCube calculateCube()
menggunakan Promises:
const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }
Batas waktu dari kode sebelumnya telah diisolasi ke dalam fungsi delay
untuk dipahami. Jika Anda mencoba memasukkan string alih-alih 4, output yang Anda dapatkan akan mirip dengan ini:

Sekali lagi, ini karena Promise
melempar kesalahan setelah semua yang lain menyelesaikan eksekusi. Solusi untuk masalah ini sederhana. Cukup tambahkan panggilan catch()
ke rantai janji seperti ini:
calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))
Sekarang outputnya akan menjadi:

Anda dapat mengamati betapa mudahnya menangani kesalahan dengan janji. Selain itu, Anda dapat menyambungkan blok finally()
dan panggilan janji untuk menambahkan kode yang akan dijalankan setelah penanganan kesalahan selesai.
Atau, Anda juga dapat menangani kesalahan dalam janji menggunakan teknik try-catch-finally tradisional. Begini tampilan janji panggilan Anda dalam kasus itu:
try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }
Namun, ini hanya berfungsi di dalam fungsi asinkron. Oleh karena itu cara yang paling disukai untuk menangani kesalahan dalam janji adalah dengan catch
rantai dan finally
ke panggilan janji.
throw/catch vs onerror() vs Callback vs Promises: Mana yang Terbaik?
Dengan empat metode yang Anda inginkan, Anda harus tahu cara memilih yang paling tepat dalam kasus penggunaan apa pun. Inilah cara Anda dapat memutuskan sendiri:
melempar/menangkap
Anda akan sering menggunakan metode ini. Pastikan untuk menerapkan kondisi untuk semua kemungkinan kesalahan di dalam blok tangkap Anda, dan ingat untuk menyertakan blok akhirnya jika Anda perlu menjalankan beberapa rutinitas pembersihan memori setelah blok coba.
Namun, terlalu banyak blok coba/tangkap dapat membuat kode Anda sulit untuk dipelihara. Jika Anda berada dalam situasi seperti itu, Anda mungkin ingin menangani kesalahan melalui penangan global atau metode janji.
Saat memutuskan antara blok try/catch asinkron dan catch()
janji, disarankan untuk menggunakan blok try/catch asinkron karena blok tersebut akan membuat kode Anda linier dan mudah di-debug.
kesalahan()
Sebaiknya gunakan metode onerror()
saat Anda tahu bahwa aplikasi Anda harus menangani banyak kesalahan, dan kesalahan itu bisa tersebar dengan baik di seluruh basis kode. Metode onerror
memungkinkan Anda menangani kesalahan seolah-olah itu hanyalah peristiwa lain yang ditangani oleh aplikasi Anda. Anda dapat menentukan beberapa penangan kesalahan dan melampirkannya ke jendela aplikasi Anda pada rendering awal.
Namun, Anda juga harus ingat bahwa metode onerror()
dapat menjadi tantangan yang tidak perlu untuk disiapkan dalam proyek yang lebih kecil dengan cakupan kesalahan yang lebih kecil. Jika Anda yakin bahwa aplikasi Anda tidak akan menimbulkan terlalu banyak kesalahan, metode lempar/tangkap tradisional akan bekerja paling baik untuk Anda.
Panggilan Balik dan Janji
Penanganan kesalahan dalam panggilan balik dan janji berbeda karena desain dan struktur kodenya. Namun, jika Anda memilih di antara keduanya sebelum Anda menulis kode, sebaiknya gunakan janji.
Ini karena janji memiliki konstruksi bawaan untuk merantai blok catch()
dan finally()
untuk menangani kesalahan dengan mudah. This method is easier and cleaner than defining additional arguments/reusing existing arguments to handle errors.
Keep Track of Changes With Git Repositories
Many errors often arise due to manual mistakes in the codebase. While developing or debugging your code, you might end up making unnecessary changes that may cause new errors to appear in your codebase. Automated testing is a great way to keep your code in check after every change. However, it can only tell you if something's wrong. If you don't take frequent backups of your code, you'll end up wasting time trying to fix a function or a script that was working just fine before.
This is where git plays its role. With a proper commit strategy, you can use your git history as a backup system to view your code as it evolved through the development. You can easily browse through your older commits and find out the version of the function working fine before but throwing errors after an unrelated change.
You can then restore the old code or compare the two versions to determine what went wrong. Modern web development tools like GitHub Desktop or GitKraken help you to visualize these changes side by side and figure out the mistakes quickly.
A habit that can help you make fewer errors is running code reviews whenever you make a significant change to your code. If you're working in a team, you can create a pull request and have a team member review it thoroughly. This will help you use a second pair of eyes to spot out any errors that might have slipped by you.
Best Practices for Handling Errors in JavaScript
The above-mentioned methods are adequate to help you design a robust error handling approach for your next JavaScript application. However, it would be best to keep a few things in mind while implementing them to get the best out of your error-proofing. Here are some tips to help you.
1. Use Custom Errors When Handling Operational Exceptions
We introduced custom errors early in this guide to give you an idea of how to customize the error handling to your application's unique case. It's advisable to use custom errors wherever possible instead of the generic Error
class as it provides more contextual information to the calling environment about the error.
On top of that, custom errors allow you to moderate how an error is displayed to the calling environment. This means that you can choose to hide specific details or display additional information about the error as and when you wish.
You can go so far as to format the error contents according to your needs. This gives you better control over how the error is interpreted and handled.
2. Do Not Swallow Any Exceptions
Even the most senior developers often make a rookie mistake — consuming exceptions levels deep down in their code.
You might come across situations where you have a piece of code that is optional to run. If it works, great; if it doesn't, you don't need to do anything about it.
In these cases, it's often tempting to put this code in a try block and attach an empty catch block to it. However, by doing this, you'll leave that piece of code open to causing any kind of error and getting away with it. This can become dangerous if you have a large codebase and many instances of such poor error management constructs.
The best way to handle exceptions is to determine a level on which all of them will be dealt and raise them until there. This level can be a controller (in an MVC architecture app) or a middleware (in a traditional server-oriented app).
This way, you'll get to know where you can find all the errors occurring in your app and choose how to resolve them, even if it means not doing anything about them.
3. Use a Centralized Strategy for Logs and Error Alerts
Logging an error is often an integral part of handling it. Those who fail to develop a centralized strategy for logging errors may miss out on valuable information about their app's usage.
An app's event logs can help you figure out crucial data about errors and help to debug them quickly. If you have proper alerting mechanisms set up in your app, you can know when an error occurs in your app before it reaches a large section of your user base.
It's advisable to use a pre-built logger or create one to suit your needs. You can configure this logger to handle errors based on their levels (warning, debug, info, etc.), and some loggers even go so far as to send logs to remote logging servers immediately. This way, you can watch how your application's logic performs with active users.
4. Notify Users About Errors Appropriately
Another good point to keep in mind while defining your error handling strategy is to keep the user in mind.
All errors that interfere with the normal functioning of your app must present a visible alert to the user to notify them that something went wrong so the user can try to work out a solution. If you know a quick fix for the error, such as retrying an operation or logging out and logging back in, make sure to mention it in the alert to help fix the user experience in real-time.
In the case of errors that don't cause any interference with the everyday user experience, you can consider suppressing the alert and logging the error to a remote server for resolving later.
5. Implement a Middleware (Node.js)
The Node.js environment supports middlewares to add functionalities to server applications. You can use this feature to create an error-handling middleware for your server.
The most significant benefit of using middleware is that all of your errors are handled centrally in one place. You can choose to enable/disable this setup for testing purposes easily.
Here's how you can create a basic middleware:
const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }
Anda kemudian dapat menggunakan middleware ini di aplikasi Anda seperti ini:
const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)
Anda sekarang dapat menentukan logika khusus di dalam middleware untuk menangani kesalahan dengan tepat. Anda tidak perlu khawatir tentang penerapan konstruksi penanganan kesalahan individual di seluruh basis kode Anda lagi.
6. Mulai Ulang Aplikasi Anda Untuk Menangani Kesalahan Programmer (Node.js)
Saat aplikasi Node.js mengalami kesalahan pemrogram, mereka mungkin tidak perlu mengeluarkan pengecualian dan mencoba menutup aplikasi. Kesalahan tersebut dapat mencakup masalah yang timbul dari kesalahan programmer, seperti konsumsi CPU yang tinggi, kembung memori, atau kebocoran memori. Cara terbaik untuk menangani ini adalah dengan memulai ulang aplikasi dengan baik dengan menghentikannya melalui mode cluster Node.js atau alat unik seperti PM2. Ini dapat memastikan bahwa aplikasi tidak mogok saat pengguna melakukan tindakan, menghadirkan pengalaman pengguna yang buruk.
7. Tangkap Semua Pengecualian yang Tidak Tertangkap (Node.js)
Anda tidak pernah bisa yakin bahwa Anda telah menutupi setiap kemungkinan kesalahan yang dapat terjadi di aplikasi Anda. Oleh karena itu, penting untuk menerapkan strategi fallback untuk menangkap semua pengecualian yang tidak tertangkap dari aplikasi Anda.
Inilah cara Anda dapat melakukannya:
process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })
Anda juga dapat mengidentifikasi apakah kesalahan yang terjadi adalah pengecualian standar atau kesalahan operasional kustom. Berdasarkan hasil, Anda dapat keluar dari proses dan memulai ulang untuk menghindari perilaku yang tidak diharapkan.
8. Tangkap Semua Penolakan Janji yang Tidak Tertangani (Node.js)
Mirip dengan bagaimana Anda tidak akan pernah bisa menutupi semua kemungkinan pengecualian, ada kemungkinan besar Anda akan kehilangan penanganan semua kemungkinan penolakan janji. Namun, tidak seperti pengecualian, penolakan janji tidak menimbulkan kesalahan.
Jadi, janji penting yang ditolak mungkin terlewatkan sebagai peringatan dan membiarkan aplikasi Anda terbuka terhadap kemungkinan mengalami perilaku yang tidak diharapkan. Oleh karena itu, sangat penting untuk menerapkan mekanisme fallback untuk menangani penolakan janji.
Inilah cara Anda dapat melakukannya:
const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
Ringkasan
Seperti bahasa pemrograman lainnya, kesalahan cukup sering terjadi dan wajar dalam JavaScript. Dalam beberapa kasus, Anda bahkan mungkin perlu membuang kesalahan dengan sengaja untuk menunjukkan respons yang benar kepada pengguna Anda. Oleh karena itu, memahami anatomi dan jenisnya sangat penting.
Selain itu, Anda perlu dilengkapi dengan alat dan teknik yang tepat untuk mengidentifikasi dan mencegah kesalahan menghapus aplikasi Anda.
Dalam kebanyakan kasus, strategi yang solid untuk menangani kesalahan dengan eksekusi yang cermat sudah cukup untuk semua jenis aplikasi JavaScript.
Apakah ada kesalahan JavaScript lain yang masih belum dapat Anda atasi? Adakah teknik untuk menangani kesalahan JS secara konstruktif? Beri tahu kami di komentar di bawah!