Belajar dengan membaca secara berurutan

Menangkap Exception — try / catch / finally

Tangkap exception dengan try dan catch, jalankan proses bersih-bersih di finally, lempar ulang dengan throw, dan bedakan penanganan menurut jenis error.

Saat kamu memakai JSON.parse untuk mengubah string yang diterima kembali menjadi object, cukup satu karakter yang salah untuk menghentikan eksekusi di baris itu, dan kode tampilan maupun penyimpanan yang kamu tulis di bawahnya tidak pernah jalan. Lagi pula, tidak semua penyebabnya bisa kamu cegah lebih dulu dengan if.

Artikel ini membahas try / catch untuk menangkap exception yang menghentikan kode, dan finally, blok yang selalu dijalankan.

Menangkap Proses yang Berhenti — try dan catch

Misalnya kamu mau mem-parse string pengaturan yang diterima dari server, lalu menerapkannya ke halaman. Kalau bentuk string-nya rusak, JSON.parse melempar exception (error yang menghentikan proses di tengah jalan) di baris itu, dan tidak ada satu pun baris di bawahnya yang dijalankan. Halaman tetap kosong dan prosesnya berhenti begitu saja.

Kalau exception terjadi di dalam try (blok yang membungkus kode yang mungkin gagal), eksekusi pindah ke catch (blok yang menerima exception). error di catch (error) hanyalah nama yang kamu berikan untuk value yang diterima (diganti err atau nama lain pun tetap jalan). Value ini punya name (nama jenis error-nya) dan message (teks penjelasannya).

// String yang masih menyisakan koma di akhir
const configText = '{"theme":"dark","fontSize":14,}';

try {
  const config = JSON.parse(configText);
  console.log(config.theme);          // baris ini tidak dijalankan
} catch (error) {
  // eksekusi pindah ke sini saat exception terjadi
  console.log("Gagal memuat pengaturan");      // Gagal memuat pengaturan
  console.log(error.name);                      // SyntaxError
}

// karena ada catch, baris berikutnya tetap jalan
console.log("Menampilkan pengaturan default");  // Menampilkan pengaturan default
Tanpa try vs. Dengan try
parse tanpatryException terjadidi baris ituTidak ada yangmenangkapBaris berikutnyatidak jalanparse di dalamtryException terjadidi baris ituPindah kecatch (error)Baris di luar trydijalankan
Di kedua cara, baris tepat di bawah baris yang melempar exception tidak dijalankan. Dengan try, kontrol pindah ke catch lalu lanjut ke baris di luar try.

Setelah pindah ke catch, eksekusi tidak kembali untuk menyelesaikan baris yang melempar exception, jadi tulis tampilan pengganti atau default value di dalam catch. Isi message berbeda-beda tergantung browser, jadi baca name kalau kamu perlu membedakan jenis error.

Ambil judul dari draft yang tersimpan. savedDraft dan brokenDraft sudah dideklarasikan.

① Di restoreTitle, parse string-nya lalu kembalikan judulnya.

② Kalau gagal, tampilkan nama jenis error-nya lalu kembalikan "Draft tanpa judul".

③ Panggil dengan kedua string, lalu tampilkan hasilnya dalam bentuk "Judul: Laporan September".

(Kalau berjalan dengan benar, penjelasan akan muncul.)

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Tetap Dijalankan Saat Berhasil Maupun Gagal — finally

Proses bersih-bersih seperti menyembunyikan indikator loading atau menutup koneksi yang terbuka tetap diperlukan, baik prosesnya berhasil maupun gagal. Kalau baris yang sama kamu tulis di try dan catch, suatu saat kamu bisa memperbaiki satu salinan dan lupa yang lain, sehingga kedua jalurnya tidak lagi berperilaku sama.

finally (blok yang selalu dijalankan saat keluar dari try) ditulis setelah catch. Entah try jalan sampai selesai atau catch menerima exception, blok ini selalu dijalankan tepat sebelum keluar. catch juga boleh dihilangkan, jadi cukup try dan finally.

function loadReport(text) {
  try {
    const report = JSON.parse(text);
    console.log(report.title);
  } catch (error) {
    console.log("Gagal memuat");
  } finally {
    // selalu dijalankan saat keluar dari try
    console.log("Indikator loading disembunyikan");
  }
}

// Saat berhasil
loadReport('{"title":"Penjualan September"}');  // Penjualan September → Indikator loading disembunyikan

// Saat gagal
loadReport('{"title":}');                       // Gagal memuat → Indikator loading disembunyikan
2 Jalur yang Berakhir di Tempat yang Sama
Kirim stringyang validtry jalansampai selesaicatchdilewatifinallydijalankanKirim stringyang rusakException terjadidi tengah trycatchmenerimanyafinallydijalankan
Baris atas dan bawah melewati rute yang berbeda, tapi ujungnya sama. finally dijalankan baik kodenya berhasil maupun gagal.

finally dijalankan setelah kode di try atau catch selesai. Karena itu, pada kode di atas, pesan bersih-bersih muncul setelah judul saat berhasil, dan setelah pesan gagal saat gagal.

Variable yang Dideklarasikan di Dalam try Tidak Bisa Dibaca dari Luar

Variable yang dideklarasikan dengan const atau let di dalam try hanya bisa dipakai di dalam blok itu. Kalau kamu membacanya dari catch, finally, atau baris setelahnya, hasilnya ReferenceError. Kalau value-nya perlu dipakai di luar try, deklarasikan variable-nya dengan let sebelum try, lalu di dalam try cukup isi value-nya.

Impor data member baris demi baris sambil menampilkan progresnya. rows dan processed sudah dideklarasikan, dan baris ke-2 bentuknya rusak.

① Parse tiap baris lalu tampilkan dalam bentuk "Budi: paket tahunan".

② Kalau parse gagal, tampilkan "Ada baris yang tidak bisa diimpor".

③ Baik berhasil maupun gagal, tambahkan 1 ke processed lalu tampilkan dalam bentuk "Diproses 1 / 3".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Memberi Tahu Pemanggil — throw di Dalam catch

Misalnya function yang membaca data reservasi menangkap exception dan hanya menulis log. Function itu lalu selesai seperti biasa, sehingga pemanggil tidak sadar ada kegagalan, terus memakai return value-nya, dan akhirnya berhenti lagi di baris lain yang jauh dari penyebab aslinya.

Kalau error yang diterima catch langsung kamu berikan ke throw (statement yang melempar exception), exception yang sama diteruskan ke pemanggil. Function-nya tetap bisa mencatat kegagalan itu sendiri, sementara keputusan cara menanganinya diserahkan ke pemanggil.

function readEntry(text) {
  try {
    return JSON.parse(text);
  } catch (error) {
    console.log(`Data reservasi tidak bisa dibaca: ${error.name}`);
    throw error;   // lempar ulang exception yang diterima apa adanya
  }
}

try {
  const entry = readEntry('{"name":"Siti","seats":}');
  console.log(entry.name);              // baris ini tidak dijalankan
} catch (error) {
  console.log("Reservasi dibatalkan");   // Reservasi dibatalkan
}
Dilempar Ulang vs. Tidak Dilempar Ulang
catch berisithrow errorSyntaxErrorditeruskan keluarcatch di luarmenerimanya"Reservasidibatalkan"catch tanpathrow errorReturn value-nyaundefinedTypeError dientry.namePemanggil dapaterror yang lain
Di baris bawah, exception berhenti di dalam function, lalu kodenya gagal lagi di baris yang membaca dari undefined. Kalau dilempar ulang, SyntaxError yang asli sampai ke pemanggil.

Kalau exception yang ditangkap di dalam function juga perlu ditangani oleh pemanggil, lempar ulang dengan menulis throw error; di akhir catch. Baris setelah throw tidak dijalankan, jadi tulis kode pencatatan log sebelum throw.

catch yang Kosong Menghilangkan Jejak Kegagalan

Kalau catch (error) { } dibiarkan kosong, exception-nya seolah hilang, tapi kegagalan itu tidak tercatat di mana pun, sehingga penyebabnya tidak bisa dilacak nanti. Akibat yang paling sering muncul adalah halaman yang tetap kosong. Selalu lakukan minimal salah satu dari ini: tampilkan pesan, pakai default value, atau lempar ulang.

Muat layout yang tersimpan. savedLayout, layout, dan errorLog sudah dideklarasikan.

① Di loadLayout, parse string-nya lalu kembalikan hasilnya.

② Kalau gagal, tambahkan nama jenis error-nya ke errorLog lalu lempar ulang.

③ Ganti layout dengan hasilnya, dan kalau gagal, tampilkan "Menampilkan layout default".

④ Tampilkan jumlah kolom dan log-nya dalam bentuk "Kolom: 2" dan "Log: SyntaxError".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Membedakan Menurut Jenis Error — instanceof dan name

catch menerima semua exception, apa pun jenisnya. Padahal pesan yang mau kamu tampilkan ke pengguna berbeda, tergantung apakah bentuk datanya rusak atau value yang mau dibaca ternyata tidak ada.

Dengan instanceof (operator yang mengecek apakah value di kiri dibuat dari jenis di kanan), kamu bisa mengecek jenisnya seperti error instanceof SyntaxError. error.name juga menyimpan nama jenis yang sama dalam bentuk string.

const applicant = { name: "Budi", contact: null };

try {
  console.log(applicant.contact.email);
} catch (error) {
  if (error instanceof SyntaxError) {
    console.log("Format datanya tidak valid");            // tidak sampai ke sini
  } else if (error instanceof TypeError) {
    console.log("Value yang mau dibaca tidak ada");       // Value yang mau dibaca tidak ada
  } else {
    console.log(`Jenis error tak terduga: ${error.name}`);
  }

  console.log(error.name);                                // TypeError
}
3 Exception, 1 catch
Exception terjadidi dalam tryparse JSONyang rusakBaca contactsaat masih nullMinta toFixed200 digitname-nyaSyntaxErrorname-nyaTypeErrorname-nyaRangeErrorBeri tahu formattidak validBeri tahu valuetidak adaCatat sebagaitak terduga
Ketiganya sampai ke catch (error) yang sama, tapi name-nya berbeda. Dengan mengecek jenisnya, kamu bisa menampilkan pesan yang berbeda.

Exception yang tidak cocok dengan pengecekan mana pun ditampung oleh else terakhir. Tabel di bawah berisi empat jenis yang sering kamu temui dan kapan masing-masing terjadi.

JenisKapan terjadiContoh kode yang memicunya
SyntaxErrorString-nya tidak berbentuk JSONJSON.parse("{,}")
TypeErrorMembaca property null atau undefinedapplicant.contact.email
RangeErrorValue di luar rentang, misal jumlah digit(1980).toFixed(200) (maksimal 100 digit)
ReferenceErrorMembaca nama yang tak dideklarasikanconsole.log(total)

Olah data berbentuk string yang dikirim sensor suhu. payloads sudah dideklarasikan, dan 2 dari 3 data itu bermasalah.

① Parse satu per satu lalu tampilkan dalam bentuk "T-1: 21.5 derajat", dengan suhu dibulatkan ke 1 angka di belakang koma.

② Kalau formatnya rusak, tampilkan "Format data yang diterima tidak valid".

③ Kalau tidak ada data suhu, tampilkan "Data suhu tidak ada".

④ Selain itu, tampilkan "Tak terduga: " diikuti nama jenis error-nya.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Apa yang ditampilkan try { console.log(1); } finally { console.log(2); }?

Soal 2Kalau catch di dalam function hanya menulis log tanpa throw error;, return value apa yang diterima pemanggil?

Soal 3Operator mana yang dipakai untuk mengecek jenis error yang diterima catch?