Panduan Definitif untuk Menangani Kesalahan dalam JavaScript

Diterbitkan: 2022-01-24

Hukum 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.

Hukum Murphy menyatakan bahwa apa pun yang bisa salah pada akhirnya akan salah Ini berlaku sedikit terlalu baik di dunia JavaScript Dapatkan persiapan dengan panduan ini Klik untuk Tweet

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:

  1. pesan : Nilai string yang membawa pesan kesalahan
  2. name : Jenis kesalahan yang terjadi (Kami akan membahasnya lebih dalam di bagian selanjutnya)
  3. 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:

Kesalahan "TypeError: Argumen numerik diharapkan" ditampilkan pada latar belakang abu-abu dengan detail tumpukan tambahan.
Contoh Jejak Tumpukan.

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:

Kesalahan "Uncaught RangeError: Ukuran tumpukan panggilan maksimum terlampaui" ditampilkan pada latar belakang merah di samping ikon palang merah dengan kode fungsi rekursif di atasnya.
Contoh RangeError dengan pemanggilan fungsi rekursif.

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:

Kesalahan "Uncaught RangeError: argumen toExponential() harus antara 0 dan 100" ditampilkan pada latar belakang merah di samping ikon palang merah dengan panggilan fungsi toExponential() di atasnya.
Contoh RangeError dengan panggilan toExponential().

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

num = 4. num.toExponential(2). Keluaran: 4.00e+0.
Output untuk panggilan fungsi toExponential().

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:

Kesalahan “Uncaught TypeError: Cannot set properties of undefined” ditampilkan pada latar belakang merah di samping ikon palang merah dengan daftar.count = 0 tugas di atasnya.
Contoh TypeError.

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

Menyetel list.count = 10 setelah menginisialisasi daftar dengan {} karena outputnya adalah 10.
Bagaimana cara memperbaiki TypeError.

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:

Kesalahan “Uncaught TypeError: Cannot read properties of undefined” ditampilkan pada latar belakang merah di samping ikon palang merah dengan func.call() di atasnya.
Contoh TypeError dengan fungsi yang tidak ditentukan.

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:

Kesalahan "tidak ditentukan bukan objek" ditampilkan pada latar belakang abu-abu.
Jejak tumpukan TypeError di browser.

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:

Daftar berpoin dengan dua item bertuliskan "Kartu 1" dan "Kartu 2".
Keluaran kode.

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.

Kesalahan "TypeError: undefined is not a object" ditampilkan pada latar belakang merah di samping ikon tanda seru merah dengan panggilan metode func.call() di atasnya.
Contoh TypeError dengan fungsi yang tidak ditentukan.

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:

Pesan kesalahan "TypeError: null is not an object", ditampilkan pada latar belakang merah di samping ikon tanda seru berwarna merah.
Contoh TypeError dengan fungsi nol.

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:

Kesalahan "Uncaught TypeError: Cannot read property 'length' of undefined" ditampilkan pada latar belakang merah di samping ikon palang merah dengan panggilan myButton.length di atasnya.
Contoh TypeError dengan objek yang tidak ditentukan.

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

Kesalahan "Uncaught TypeError: Cannot read properties of undefined" ditampilkan pada latar belakang merah di samping ikon palang merah dengan panggilan myButton.length di atasnya.
Contoh TypeError dengan objek yang tidak ditentukan pada versi Chrome yang lebih baru.

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:

Kesalahan “Uncaught TypeError: Assignment to constant variable” ditampilkan pada latar belakang merah di samping ikon palang merah dengan fungsi = 6 penetapan di atasnya.
Contoh TypeError dengan penugasan objek konstan.

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:

  1. Tambahkan atribut crossorigin di tag skrip.
  2. Setel tajuk Access-Control-Allow-Origin yang benar di server yang menghosting skrip.
  3. [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 objek Error .
  • 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:

Kesalahan "Kesalahan Tidak Tertangkap: Argumen numerik diharapkan" ditampilkan pada latar belakang merah tua di samping ikon palang merah.
Contoh kesalahan dengan argumen yang salah.

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:

Pesan "TypeError: Argumen numerik diharapkan" ditampilkan pada latar belakang abu-abu gelap.
Contoh TypeError dengan argumen ilegal.

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:

Kesalahan "Tidak tertangkap (dalam janji) Kesalahan: Argumen numerik diharapkan" ditampilkan pada latar belakang abu-abu gelap di samping ikon palang merah.
Contoh TypeError dengan argumen ilegal di Promise.

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:

Pesan "Kesalahan: Argumen numerik diharapkan" ditampilkan pada latar belakang abu-abu gelap.
Menangani contoh TypeError dengan argumen ilegal.

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)
Jika Anda membuat aplikasi, ada kemungkinan Anda juga akan membuat bug dan masalah lain di dalamnya. Pelajari cara menanganinya dengan bantuan dari panduan ini ️ Klik untuk Tweet

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!