15 Desember 2021

Penanganan eror, "try..catch"

Tidak peduli seberapa hebatnya kita dalam pemograman, terkadang kodingan kita memiliki banyak eror. Mereka mungkin muncul dikarenakan kesalahan kita, input dari user yang tidak terduga, eror respon dari server, dan juga berbagai macam alasan lainnya.

Biasanya, sebuah kodingan/scrip “terhenti” (tiba-tiba berhenti) dikarenakan adanya eror, menampilkan erornya pada console.

Tapi terdapat sebuah sintaks try..catch yang memperbolehkan kita untuk “menangkap” hasil eror sehingga skrip bisa berjalan sesuai dengan arahan kita, dibanding hanya berhenti saja.

Sintaks “try…catch”

Sintaks try..catch membentuk dua bagian utama: pertama try, dan kemudian catch:

try {

  // kodingan disini

} catch (err) {

  // Penanganan jika eror

}

Mereka akan bekerja seperti ini:

  1. Pertama, kodingan pada try {...} akan dijalankan.
  2. Jika tidak terdapat eror, maka catch(err) akan dihiraukan: prosesnya akan mencapai ujung bagian try dan kemudian berlanjut, melewati bagian catch.
  3. Jika terdapat eror, maka bagian try akan berhenti berjalan, dan alur prosesnya akan berlanjut pada awal bagian catch(err). Variabel err (yang mana kita bisa ganti dengan nama apapun) akan mengandung eror objek dengan keterangan eror didalamnya.

Jadi, sebuah eror didalam bagian try {…} tidak akan memberhentikan kodingan tersebut – kita memiliki sebuah kesempatan untuk menanganinya pada bagian catch.

Mari kita lihat contoh lainnya.

  • Sebuah contoh tanpa eror: menampilkan alert (1) dan (2):

    try {
    
      alert('Start of try runs');  // (1) <--
    
      // ...tidak ada eror disini
    
      alert('End of try runs');   // (2) <--
    
    } catch (err) {
    
      alert('Catch is ignored, because there are no errors'); // (3)
    
    }
  • Sebuah contoh dengan eror: shows (1) dan (3):

    try {
    
      alert('Start of try runs');  // (1) <--
    
      lalala; // error, variable is not defined!
    
      alert('End of try (never reached)');  // (2)
    
    } catch (err) {
    
      alert(`Error has occurred!`); // (3) <--
    
    }
try..catch hanya akan bekerja pada eror runtime

Untuk try..catch agar bekerja, kodingan tersebut harus bisa dijalankan. Dengan artian lain, itu harus dalam bahasa javascript yang valid.

Mereka tidak akan bekerja jika kodingan tersebut secara sintaks salah, sebagai contoh jika mereka memiliki kurung kurawal yang tidak sama:

try {
  {{{{{{{{{{{{
} catch (err) {
  alert("The engine can't understand this code, it's invalid");
}

Mesin Javascript pertama membaca kodingan tersebut, dan menjalankannya. eror yang terjadi pada saat proses pembacaan disebut sebagai eror “parse-time” dan tidak dapat dipulihkan (dari dalam kodingan tersebut). Itu dikarenakan mesin javascript tidak mengerti kodingan .

Jadi, try..catch hanya dapat menangani eror yang terjadi pada kodingan yang valid. eror demikian biasanya dinamakan sebagai “eror runtime” atau terkadang, “exceptions”.

try..catch bekerja secara sinkronis

Jika sebuah exception terjadi pada kodingan yang “terjadwal”, seperti pada setTimeout, maka try..catch tidak akan menangkapnya:

try {
  setTimeout(function() {
    noSuchVariable; // kodingan akan berhenti disini
  }, 1000);
} catch (err) {
  alert( "won't work" );
}

Itu dikarenakan fungsi tersebut dijalankan nanti, ketika mesin javascript telah meninggalkan bagian pada try..catch.

Untuk menangkap sebuah exception didalam sebuah fungsi yang terjadwal, try..catch harus terjadi didalam fungsi tersebut:

setTimeout(function() {
  try {
    noSuchVariable; // try..catch menangani eror tersebut!
  } catch {
    alert( "error is caught here!" );
  }
}, 1000);

Eror Objek

Ketika sebuah eror terjadi, Javascript menghasilkan sebuah ojek yang berisikan keterangan terkait eror tersebut. Objek itu kemudian dilewatkan sebagai sebuah argumen pada bagian catch:

try {
  // ...
} catch(err) { // <-- "error object", bisa menggunakan kata lain selain err
  // ...
}

Untuk semua eror bawaan, eror objek memiliki dua properti utama:

name
Nama error. sebagai contoh, untuk variable yang belum terdefinisikan maka itu disebut "ReferenceError".
message
Pesan yang ada didalam eror tersebut.

Terdapat properti non-standard lainnya pada kebanyakan Ada properti non-standar lain yang tersedia di sebagian besar lingkungan. Salah satu yang paling banyak digunakan dan didukung ialah:

stack
Call stack saat ini: string dengan informasi tentang urutan panggilan bertingkat yang menyebabkan kesalahan. Digunakan untuk tujuan debugging.

Sebagai contoh:

try {
  lalala; // error, variable is not defined!
} catch (err) {
  alert(err.name); // ReferenceError
  alert(err.message); // lalala is not defined
  alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)

  // Can also show an error as a whole
  // The error is converted to string as "name: message"
  alert(err); // ReferenceError: lalala is not defined
}

“Catch” binding Opsional

Tambahan baru-baru ini
Ini adalah tambahan terbaru untuk bahasa ini. Browser lama mungkin memerlukan polyfill.

Jika kita tidak butuh detail tentang eror, catch mungkin bisa menghilangkannya:

try {
  // ...
} catch { // <-- tanpa (err)
  // ...
}

Menggunakan “try…catch”

Mari kita telusuri contoh penggunaan nyata dari try..catch.

Seperti yang telah kita ketahui, Javascript mendukung method JSON.parse(str) yang membaca dari nilai JSON-encoded.

Biasanya digunakan untuk memecahkan kode data yang diterima melalui jaringan, dari server atau sumber lain.

Kita menerimanya dan memanggil JSON.parse seperti ini:

let json = '{"name":"John", "age": 30}'; // data dari server

let user = JSON.parse(json); // mengonversi representasi teks ke objek JS

// sekarang pengguna adalah objek dengan properti dari string
alert( user.name ); // John
alert( user.age );  // 30

Kalian dapat menemukan informasi lebih detail tentang JSON di bab <info: json>.

Jika format json salah,JSON.parse menghasilkan error, sehingga skrip “mati”.

Cukupkah kita puas dengan itu? Tentu saja tidak!

Dengan cara ini, jika ada yang salah dengan datanya, pengunjung tidak akan pernah mengetahuinya (kecuali mereka membuka konsol pengembang). Dan orang biasanya tidak suka ketika sesuatu “berhenti begitu saja” tanpa ada pesan kesalahan.

Mari gunakan try..catch untuk menangani kesalahan:

let json = "{ bad json }";

try {

  let user = JSON.parse(json); // <-- ketika terjadi sebuah eror...
  alert( user.name ); // tidak berjalan

} catch (err) {
  // ...proses eksekusinya akan lompat kesini
  alert( "Our apologies, the data has errors, we'll try to request it one more time." );
  alert( err.name );
  alert( err.message );
}

Di sini kita menggunakan blok catch hanya untuk menampilkan pesan, tetapi kita dapat melakukan lebih banyak lagi: mengirim permintaan jaringan baru, menyarankan alternatif kepada pengunjung, mengirim informasi tentang kesalahan ke fasilitas logging, …. Semuanya jauh lebih baik daripada sekedar mati.

Melontarkan eror kita sendiri

Bagaimana jika json secara sintaksis benar, tetapi tidak memiliki propertiname yang diperlukan?

Seperti ini:

let json = '{ "age": 30 }'; // data tidak lengkap

try {

  let user = JSON.parse(json); // <-- tidak ada eror
  alert( user.name ); // tidak ada nama!

} catch (err) {
  alert( "doesn't execute" );
}

Di sini JSON.parse berjalan normal, tetapi tidak adanyanama sebenarnya merupakan eror bagi kita.

Untuk menyatukan penanganan error, kita akan menggunakan operator throw.

Operator “Throw”

Operator throw menghasilkan sebuah eror.

Sintaksnya adalah:

throw <error object>

Secara teknis, kita dapat menggunakan apapun sebagai eror objek. Technically, we can use anything as an error object. Itu bahkan mungkin dengan data primitif, seperti angka atau string, lebih disarankan menggunakan objek, dan juga dengan properti name danmessage (agar tetap kompatibel dengan error bawaan).

JavaScript memiliki banyak konstruktor bawaan untuk standar eror: Error, SyntaxError,ReferenceError, TypeError dan lain-lain. Kita bisa menggunakannya untuk membuat eror objek juga.

Sintaksnya adalah:

let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...

Untuk eror bawaan (bukan untuk objek lainnya, hanya untuk eror), properti name persis dengan nama konstruktornya. Dan pesan diambil dari argumennya.

Sebagai contoh: