coba-tangkap dalam javascript ... bukankah itu praktik yang baik?

69

Ada ketentuan untuk blok try-catch dalam javascript . Sementara di java atau bahasa lain itu wajib untuk memiliki penanganan kesalahan, saya tidak melihat siapa pun menggunakannya dalam javascript untuk tingkat yang lebih besar. Bukankah ini praktik yang baik atau kita tidak membutuhkannya dalam javascript?

akp
sumber
2
While in java or *any other language* it is mandatory to have error handling...- Tidak juga. Java, ya, tetapi ada banyak bahasa yang tidak memaksa try-catch (seperti C #).
Jim G.
Itu karena Anda tidak dapat menggunakannya di lingkungan async. Saya sering menggunakannya dengan menyinkronkan kode dengan tingkat abstraksi yang lebih rendah, misalnya dengan mengubah sesuatu menjadi sesuatu, dll ...
inf3rno
Saya yakin Anda akan melihat lebih banyak try-catch dalam kode sisi server daripada kode sisi klien. Sebagian besar kode sisi klien yang Anda ketahui tidak melakukan hal yang penting. Saya ingin meminimalkan KB di pipa lebih penting daripada memulihkan dari setiap kesalahan - dalam sebagian besar aplikasi dan keadaan sisi browser.
svidgen
Ada satu cara lain untuk menghindari coba tangkap menggunakan mungkin dan Either (monads) kami memiliki web scrapper yang ditulis dalam node. Kami dapat menghapus semua tangkapan mencoba menggunakannya.
user93

Jawaban:

66

Orang harus menghindari throwkesalahan sebagai cara untuk melewati kondisi kesalahan di dalam aplikasi.

The throwpernyataan seharusnya hanya digunakan "Untuk ini seharusnya tidak pernah terjadi, kecelakaan dan terbakar. Jangan pulih elegan dengan cara apapun"

try catch Namun digunakan dalam situasi di mana objek host atau ECMAScript dapat melempar kesalahan.

Contoh:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

Rekomendasi dalam komunitas node.js adalah agar Anda meneruskan kesalahan dalam panggilan balik (Karena kesalahan hanya terjadi untuk operasi asinkron) sebagai argumen pertama

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

Ada juga masalah lain seperti try / catch yang sangat mahal dan jelek dan tidak bekerja dengan operasi asinkron.

Jadi karena operasi sinkron tidak boleh melempar kesalahan dan tidak bekerja dengan operasi asinkron, tidak ada yang menggunakan try catch kecuali untuk kesalahan yang dilemparkan oleh objek host atau ECMAScript

Raynos
sumber
2
Saya tidak akan mengatakan bahwa tidak ada yang menggunakan try catch, itu hanya alat yang salah untuk pekerjaan dalam banyak kasus. Ketika ada keadaan yang benar-benar luar biasa, itu bisa bermanfaat untuk melempar Error, tetapi mereka sedikit dan jarang.
zzzzBov
7
@zzzzBov Tidak ada yang salah dengan melempar kesalahan untuk huruf C, rusak dan bakar. Saya hanya tidak berpikir Anda harus menangkap kesalahan dan memulihkan. Misalnya document.getElementByIdtidak melempar ketika elemen tidak ada, itu hanya mengembalikan null. Hal yang sama dapat dilakukan untuk hampir semua kasus
Raynos
4
@ Raynos, melempar dari fungsi sinkronisasi benar-benar dapat diterima dan masuk akal dalam kasus penggunaan itu. Mengembalikan kesalahan ke panggilan balik adalah ke async karena kesalahan melempar adalah untuk menyinkronkan.
sbartell
@Raynos punya saran bagus untuk menghindari penggunaan Kesalahan / Pengecualian untuk kontrol aliran di sisi klien (lingkungan non-Node)? Saya telah menemukan posting ini di StackOverflow , tetapi sebagian besar diarahkan ke Jawa
blong
@ b, panjang sederhana. jangan pernah melakukan kesalahan. Masalah terpecahkan.
Raynos
32

Coba / tangkap dalam Javascript tidak semudah peluru di bahasa lain, karena sifat asinkron Javascript. Pertimbangkan cuplikan ini:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

Masalahnya adalah bahwa aliran kontrol meninggalkan tryblok sebelum do_something_that_throws()dieksekusi, sehingga kesalahan yang dilemparkan ke dalam callback tidak pernah tertangkap.

Jadi coba / tangkap pada dasarnya tidak sesuai dalam banyak kasus, dan tidak selalu jelas apakah sesuatu mengeksekusi kode secara tidak sinkron atau tidak. Untungnya, javascript dengan idiom single-threaded-asynchronous-callback yang aneh dan dukungannya untuk penutupan aktual memberikan alternatif yang elegan: penanganan kesalahan gaya kelanjutan-lewat. Cukup berikan respons yang tepat untuk kesalahan apa pun sebagai fungsi, misalnya:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);
tammmer
sumber
5
itu juga bukan bukti peluru dalam bahasa lain. Port kode itu ke bahasa apa pun yang mendukung panggilan balik asinkron dan itu akan gagal juga.
Raynos
2
@ Raynos: Anda benar; Namun, bahasa lain (atau lebih tepatnya, budaya pendukungnya) tidak terlalu banyak membeli ini ke dalam idiom panggilan balik asinkron seperti yang dilakukan Javascript, dan karena sifat multi-utas dari sebagian besar lingkungan lain, kekurangan try / catch lebih jelas dan dikelilingi oleh banyak peringatan lainnya, sehingga orang secara alami melangkah hati-hati dalam situasi callback multi-threaded / asinkron, dan lebih menyadari potensi jebakan.
tdammers
Apakah ini benar-benar karena JavaScript "asynchronous nature?" Sejauh yang saya bisa lihat, Coba / Tangkap secara teoritis dapat dibuat untuk bekerja secara leksikal seperti bagaimana pengidentifikasi ditutup secara leksikal; itu tidak terjadi seperti itu dalam JavaScript.
Brian Gordon
2
Dalam node.js> = 0,8 perlu dicatat adalah mungkin untuk mencoba / menangkap secara tidak sinkron, silakan lihat pertanyaan saya stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum
Apakah satu-satunya alternatif untuk try-catch sinkron adalah gaya passing kelanjutan asinkron?
CMCDragonkai
23

Banyak dari jawaban ini agak lama dan tidak memperhitungkan fitur ES7 baru asyncdan await.

Menggunakan async/ awaitAnda sekarang bisa mendapatkan aliran kontrol asinkron seperti yang Anda inginkan:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: '[email protected]`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

Pelajari lebih lanjut tentang async/ di awaitsini . Anda dapat menggunakan async/ awaitsekarang menggunakan babel .

Dana Woodman
sumber
Tetapi mirip dengan kode sinkron
Atul Agrawal
@AtulAgrawal ya, itu intinya. Async / await memungkinkan Anda untuk menulis kode async dengan gaya sinkron sehingga Anda dapat menghindari "panggilan balik neraka" dan merantai banyak janji bersama. Ini cara yang sangat menyenangkan untuk menulis kode async menurut saya
Dana Woodman
jadi apa untungnya menggunakan javascript jika kita membuat kode async menjadi sinkron. karena sebagian besar orang menggunakan javascript karena sifatnya yang async
Atul Agrawal
2
@AtulAgrawal Anda mendapatkan yang terbaik dari kedua dunia - Anda menikmati sifat async bahasa (karena kode di atas masih akan dieksekusi async - membebaskan utas dan semuanya) dan merobek manfaat dari gaya pengkodean yang lebih ramah-programmer. Ini bukan tanpa masalah, ...
ZenMaster
15

try-catch dalam javascript sama valid dan bermanfaatnya dengan bahasa lain yang mengimplementasikannya. Ada satu alasan utama mengapa tidak banyak digunakan dalam javascript seperti dalam bahasa lain. Itu alasan yang sama javascript dilihat sebagai bahasa skrip yang jelek, itu alasan yang sama mengapa orang berpikir programmer javascript bukan programmer nyata:

  • Javascript adalah bahasa yang sangat mudah diakses dan meresap

Fakta bahwa begitu banyak orang terkena javascript (berdasarkan satu-satunya bahasa yang didukung oleh browser) berarti Anda memiliki banyak kode tidak profesional di luar sana. Tentu saja ada juga banyak alasan kecil:

  • beberapa hal dalam javascript asinkron dan karenanya tidak catchdapat (asinkron)
  • ada banyak pembicaraan berlebihan tentang bagaimana try-catch memiliki kinerja yang luar biasa. Ini memiliki sedikit hit kinerja , tetapi untuk sebagian besar kode, itu sangat berharga.
  • javascript (sayangnya) diimplementasikan dengan cara yang sering mengabaikan kesalahan secara diam-diam (misalnya mengubah string ke angka secara otomatis)

Apapun, try-catch harus digunakan, tetapi tentu saja Anda harus belajar bagaimana menggunakannya dengan benar - seperti yang lainnya dalam pemrograman.

pengguna250878
sumber
3
Dan mengapa Anda pernah downvote, oh silent downvoter?
user250878
Sepakat. Saya pikir jawaban yang diterima umumnya benar, tetapi ada alasan bagus untuk menggunakan try-catch, dan bahkan melempar, selain ketika berhadapan dengan objek asli. Ketika sebuah kesalahan dilemparkan alih-alih diteruskan ke panggilan balik, itu menghentikan eksekusi lebih lanjut dan melompati tumpukan ke blok pertama daripada yang bisa mengatasinya. Ini adalah keuntungan besar dan sangat masuk akal untuk operasi sinkron, terutama jika mereka melibatkan penyatuan yang dalam. Tampaknya gila untuk menyarankan pengecualian itu "buruk" (yah, selain karena alasan yang jelas) - mereka sebenarnya alat yang sangat berguna dengan "kekuatan" yang unik.
Titik koma
2
Apakah Anda pernah meluangkan waktu untuk membaca kode sumber, katakanlah, jQuery? Hampir tidak ada try-catch di sana kecuali untuk persis skenario yang disebutkan dalam jawaban yang diterima: untuk mendeteksi fitur dan menggunakan objek asli / host yang melempar kesalahan. Untuk memanggil kode yang tidak menggunakan coba-tangkap banyak (seperti jQuery) 'tidak profesional' tampak konyol. Sejujurnya, saya pikir itu terutama programmer Javascript baru yang berasal dari Jawa yang cenderung menggunakan fitur-fitur bahasa seperti try-catch.
Stijn de Witt
6

Saya percaya bahwa banyak alasan yang try..catchjarang ada dalam JavaScript adalah karena bahasa tersebut memiliki toleransi yang cukup tinggi untuk kesalahan. Sebagian besar situasi dapat ditangani dengan menggunakan pemeriksaan kode, default yang baik, dan peristiwa asinkron. Dalam beberapa kasus, hanya menggunakan pola akan mencegah masalah:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Beberapa masalah utama dalam bahasa lain yang menyebabkan pengecualian hanya tidak ada di JS. Pengecoran tipe tidak diperlukan sebagian besar waktu. Alih-alih, metode yang lebih disukai biasanya untuk memeriksa fitur (menjalankan antarmuka tertentu):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

Dengan penambahan async/ awaitke bahasa, try..catchmenjadi lebih lazim. Menjanjikan sebagai bentuk asinkron try..catch, masuk akal bahwa seseorang harus mengharapkan:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

alih-alih ditulis sebagai:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}
zzzzBov
sumber
3

Mungkin alasan lain mencoba / menangkap tidak banyak digunakan dalam Javascript adalah konstruk tidak tersedia dalam versi pertama Javascript ... ditambahkan kemudian.

Akibatnya, beberapa browser lama tidak mendukungnya. (Faktanya, ini dapat menyebabkan kesalahan parser / sintaksis di beberapa browser lama, sesuatu yang lebih sulit untuk "diprogram secara defensif" dibandingkan dengan kebanyakan jenis kesalahan lainnya.)

Lebih penting lagi, karena awalnya tidak tersedia, fungsi built-in Javascript yang awalnya dirilis (apa yang disebut fungsi "perpustakaan" dalam banyak bahasa) tidak memanfaatkannya. (Tidak berfungsi dengan baik untuk "menangkap" kesalahan dari someobject.somefunction () jika tidak "melempar" tetapi sebaliknya hanya mengembalikan "null" ketika mengalami masalah.)


Namun alasan lain yang mungkin adalah mekanisme coba / tangkap tampaknya tidak diperlukan pada awalnya (dan masih tampak tidak terlalu berguna). Ini benar-benar diperlukan hanya ketika panggilan secara rutin bersarang beberapa level; hanya mengembalikan semacam ERRNO akan berfungsi dengan baik untuk panggilan langsung (walaupun untuk membuatnya sangat berguna kapan pun itu tersedia, praktik terbaik dalam kebanyakan bahasa adalah menggunakannya di mana - mana daripada hanya pada panggilan yang sangat bersarang). Karena logika Javascript pada awalnya diharapkan kecil dan sederhana (setelah semua, itu hanya tambahan untuk halaman web :-), panggilan fungsi tidak diharapkan untuk bersarang secara mendalam, dan mekanisme mencoba / menangkap sepertinya tidak diperlukan.

Chuck Kollars
sumber
3
Tidak, tidak, tidak sama sekali. Mesin yang lama tidak penting lagi untuk waktu yang lama dan komunitas javascript pada umumnya cepat untuk menjatuhkan hal-hal lama ketika dibenarkan. Saya bahkan berani bertaruh bahwa mayoritas pengembang javascript sekarang adalah post-IE6.
Camilo Martin
0

Saya percaya mereka tidak banyak digunakan karena melemparkan pengecualian dalam kode sisi klien Javascript membuatnya lebih sulit untuk men-debug halaman.

Daripada melemparkan pengecualian, saya biasanya lebih suka menampilkan kotak al alert, (yaitu alert("Error, invalid...");)

Ini mungkin terdengar aneh, tetapi kesalahan Javascript terjadi di sisi klien, jika pelanggan menggunakan halaman yang Anda buat dan halaman melempar pengecualian, kecuali jika pelanggan adalah seorang tech-savvy-coder tidak ada cara dia akan pernah bisa memberitahu apa masalahnya.

Dia hanya akan memanggil Anda dengan mengatakan: "Hei, halaman X tidak bekerja!", Dan kemudian terserah kepada Anda untuk menemukan apa yang salah dan di mana dalam kode.

Dengan menggunakan kotak peringatan sebagai gantinya, lebih mungkin dia menelepon dan mengatakan sesuatu seperti: "Hei, ketika saya mengklik tombol A halaman X itu menunjukkan kotak yang mengatakan ..." , percayalah, akan lebih mudah untuk menemukan serangga.

Marco Demaio
sumber