Katakanlah saya memiliki fungsi ini mengotentikasi yang mengembalikan janji. Janji itu kemudian diselesaikan dengan hasilnya. Salah dan benar adalah hasil yang diharapkan, seperti yang saya lihat, dan penolakan hanya boleh terjadi dalam kasus kesalahan. Atau, apakah kegagalan dalam otentikasi dianggap sebagai sesuatu yang Anda tolak janji?
javascript
Mathieu Bertin
sumber
sumber
reject
dan tidak kembali palsu, tetapi jika Anda mengharapkan nilai menjadiBool
, maka Anda berada sukses dan Anda harus menyelesaikan dengan Bool terlepas dari nilai. Janji adalah semacam proxy untuk nilai - mereka menyimpan nilai yang dikembalikan, jadi hanya jika nilainya tidak dapat diperoleh jika Andareject
. Kalau tidak, Anda seharusnyaresolve
.false
atau sebagai melemparkan pengecualian?then
ketika server merespons - bahkan jika kode kesalahan dikembalikan - dan Anda harus memeriksaresponse.ok
. Thecatch
handler hanya dipicu untuk tak terduga kesalahan.Jawaban:
Pertanyaan bagus! Tidak ada jawaban yang sulit. Itu tergantung pada apa yang Anda anggap istimewa pada titik tertentu dari aliran itu .
Menolak
Promise
adalah sama dengan memunculkan pengecualian. Tidak semua hasil yang tidak diinginkan luar biasa , hasil dari kesalahan . Anda bisa memperdebatkan kasus Anda dengan dua cara:Otentikasi yang gagal harus
reject
menjadiPromise
, karena pemanggil mengharapkanUser
objek sebagai imbalan, dan hal lain merupakan pengecualian untuk aliran ini.Otentikasi gagal harus
resolve
yangPromise
, meskipun untuknull
, karena memberikan kepercayaan yang salah adalah tidak benar-benar luar biasa kasus, dan penelepon tidak mengharapkan aliran untuk selalu menghasilkanUser
.Perhatikan bahwa saya melihat masalah dari sisi pemanggil . Dalam arus informasi, apakah penelepon mengharapkan tindakannya menghasilkan
User
(dan apa pun yang salah), atau apakah masuk akal bagi penelepon khusus ini untuk menangani hasil lainnya?Dalam sistem multi-layered, jawabannya dapat berubah saat data mengalir melalui lapisan. Sebagai contoh:
null
pengguna.Contoh 4 poin ini jelas rumit, tetapi menggambarkan 2 poin:
Jadi sekali lagi, tidak ada jawaban yang sulit. Saatnya berpikir dan mendesain!
sumber
Jadi Janji memiliki properti yang bagus yang mereka bawa JS dari bahasa fungsional, yaitu bahwa mereka memang mengimplementasikan
Either
konstruktor tipe ini yang merekatkan dua tipe lainnya,Left
tipe danRight
tipe, dengan memaksa logika untuk mengambil satu cabang atau yang lain cabang.Sekarang Anda benar-benar memperhatikan bahwa tipe di sisi kiri tidak jelas untuk janji; Anda bisa menolak dengan apa pun. Ini benar karena JS diketik dengan lemah, tetapi Anda ingin berhati-hati jika Anda memprogram pertahanan.
Alasannya adalah bahwa JS akan mengambil
throw
pernyataan dari kode penanganan janji dan menggabungkannya keLeft
sisi itu juga. Secara teknis di JS Anda dapatthrow
segalanya, termasuk true / false atau string atau angka: tetapi kode JavaScript juga melempar sesuatu tanpathrow
(ketika Anda melakukan hal-hal seperti mencoba mengakses properti pada nulls) dan ada API menetap untuk ini (Error
objek) . Jadi ketika Anda berkeliling untuk menangkap, biasanya baik untuk dapat menganggap bahwa kesalahan itu adalahError
objek. Dan karenareject
untuk janji akan menggumpal dalam kesalahan dari salah satu bug di atas, Anda biasanya hanya inginthrow
kesalahan lain, untuk membuatcatch
pernyataan Anda memiliki logika yang sederhana dan konsisten.Oleh karena itu meskipun Anda dapat menempatkan jika-kondisional di Anda
catch
dan mencari kesalahan palsu, dalam hal ini kasus kebenaran itu sepele,Anda mungkin akan lebih suka struktur logika, setidaknya untuk apa yang keluar langsung dari autentikator, dari boolean yang lebih sederhana:
Bahkan level berikutnya dari logika otentikasi mungkin adalah untuk mengembalikan beberapa jenis
User
objek yang berisi pengguna yang diautentikasi, sehingga ini menjadi:dan ini kurang lebih seperti yang saya harapkan: return
null
dalam kasus di mana pengguna tidak didefinisikan, jika tidak kembali{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Aku berharap bahwa kasus umum dari tidak sedang login adalah diselamatkan, misalnya jika kita berada di semacam "demo untuk klien baru" mode, dan tidak boleh dicampur dengan bug di mana saya sengaja dipanggilobject.doStuff()
saatobject.doStuff
ituundefined
.Sekarang dengan mengatakan, apa yang mungkin ingin Anda lakukan adalah mendefinisikan
NotLoggedIn
atauPermissionError
pengecualian yang berasal dariError
. Kemudian dalam hal-hal yang benar-benar membutuhkannya Anda ingin menulis:sumber
Kesalahan
Mari kita bicara tentang kesalahan.
Ada dua jenis kesalahan:
Kesalahan yang Diharapkan
Kesalahan yang diharapkan adalah keadaan di mana hal yang salah terjadi tetapi Anda tahu bahwa itu mungkin terjadi, jadi Anda menanganinya.
Ini adalah hal-hal seperti input pengguna atau permintaan server. Anda tahu pengguna mungkin membuat kesalahan atau bahwa server mungkin turun, jadi Anda menulis beberapa kode pemeriksaan untuk memastikan bahwa program meminta input lagi, atau menampilkan pesan, atau apa pun perilaku lain yang sesuai.
Ini dapat dipulihkan saat ditangani. Jika dibiarkan, mereka menjadi kesalahan yang tidak terduga.
Kesalahan Tidak Terduga
Kesalahan tak terduga (bug) adalah keadaan di mana hal yang salah terjadi karena kode salah. Anda tahu bahwa mereka pada akhirnya akan terjadi, tetapi tidak ada cara untuk mengetahui di mana atau bagaimana menghadapinya karena, menurut definisi, mereka tidak terduga.
Ini adalah hal-hal seperti kesalahan sintaksis dan logika. Anda mungkin memiliki kesalahan ketik dalam kode Anda, Anda mungkin telah memanggil fungsi dengan parameter yang salah. Ini biasanya tidak dapat dipulihkan.
try..catch
Mari kita bicarakan
try..catch
.Dalam JavaScript,
throw
tidak umum digunakan. Jika Anda mencari-cari contoh dalam kode mereka akan sedikit dan jauh di antara, dan biasanya terstruktur di sepanjang barisKarena itu,
try..catch
blok tidak terlalu umum untuk aliran kontrol. Biasanya cukup mudah untuk menambahkan beberapa cek sebelum memanggil metode untuk menghindari kesalahan yang diharapkan.Lingkungan JavaScript juga cukup memaafkan, sehingga kesalahan yang tak terduga seringkali juga diabaikan.
C # :try..catch
tidak harus biasa. Ada beberapa kasus penggunaan yang bagus, yang lebih umum dalam bahasa seperti Java dan C #. Java dan C # memiliki keunggulan mengetikcatch
konstruksi yang , sehingga Anda dapat membedakan antara kesalahan yang diharapkan dan yang tidak terduga:Contoh ini memungkinkan pengecualian tak terduga lainnya mengalir dan ditangani di tempat lain (seperti dengan cara login dan menutup program).
Dalam JavaScript, konstruk ini dapat direplikasi melalui:
Bukan sebagai elegan, yang merupakan bagian dari alasan mengapa itu tidak biasa.
Fungsi
Mari kita bicara tentang fungsi.
Jika Anda menggunakan prinsip tanggung jawab tunggal , setiap kelas dan fungsi harus melayani tujuan tunggal.
Sebagai contoh
authenticate()
dapat mengotentikasi pengguna.Ini dapat ditulis sebagai:
Atau dapat juga ditulis sebagai:
Keduanya bisa diterima.
Janji
Mari kita bicara tentang janji.
Janji adalah bentuk asinkron dari
try..catch
. Memanggilnew Promise
atauPromise.resolve
memulaitry
kode Anda . Memanggilthrow
atauPromise.reject
mengirim Anda kecatch
kode.Jika Anda memiliki fungsi asinkron untuk mengautentikasi pengguna, Anda dapat menuliskannya sebagai:
Atau dapat juga ditulis sebagai:
Keduanya bisa diterima.
Bersarang
Mari kita bicara tentang bersarang.
try..catch
bisa disarangkan.authenticate()
Metode Anda mungkin secara internal memilikitry..catch
blok seperti:Demikian juga janji bisa disarangkan.
authenticate()
Metode async Anda mungkin menggunakan janji secara internal:Jadi apa jawabannya?
Ok, saya pikir sudah waktunya bagi saya untuk benar-benar menjawab pertanyaan:
Jawaban paling sederhana yang bisa saya berikan adalah bahwa Anda harus menolak janji di mana pun Anda ingin
throw
pengecualian jika itu kode sinkron.Jika aliran kontrol Anda lebih sederhana dengan melakukan beberapa
if
pemeriksaan dalamthen
laporan Anda , tidak perlu menolak janji.Jika aliran kontrol Anda lebih sederhana dengan menolak janji dan kemudian memeriksa jenis kesalahan dalam kode penanganan kesalahan Anda, maka lakukan itu.
sumber
Saya telah menggunakan cabang "tolak" dari Janji untuk mewakili aksi "batal" dari kotak dialog jQuery UI. Tampaknya lebih alami daripada menggunakan cabang "menyelesaikan", paling tidak karena sering ada beberapa opsi "tutup" pada kotak dialog.
sumber
Menangani janji kurang lebih seperti kondisi "jika". Terserah Anda apakah Anda ingin "menyelesaikan" atau "menolak" jika otentikasi gagal.
sumber
try..catch
, bukanif
.try...catch
dan hanya mengatakan bahwa jika Anda dapat menyelesaikan dan mendapatkan hasil, Anda harus menyelesaikan terlepas dari nilai yang diterima, jika tidak, Anda harus menolak?try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
baik-baik saja, tetapi konstruksi yangPromise
mewakili adalahtry..catch
bagian, bukanif
bagian.doSomething()
gagal, maka itu akan melempar, tetapi jika tidak bisa mengandung nilai yang Anda butuhkan (diif
atas Anda sedikit membingungkan karena itu bukan bagian dari ide Anda di sini :)). Anda hanya boleh menolak jika ada alasan untuk melempar (dalam analogi), jadi jika tes gagal. Jika tes berhasil, Anda harus selalu menyelesaikannya, terlepas dari apakah nilainya positif, bukan?