Saya masih cukup baru dalam promise dan saya menggunakan bluebird saat ini, namun saya memiliki skenario di mana saya tidak begitu yakin bagaimana cara terbaik untuk menghadapinya.
Jadi misalnya saya memiliki rantai janji dalam aplikasi ekspres seperti:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Jadi perilaku yang saya kejar adalah:
- Pergi untuk mendapatkan akun dengan Id
- Jika ada penolakan pada saat ini, bom dan kembalikan kesalahan
- Jika tidak ada kesalahan, ubah dokumen dikembalikan ke model
- Verifikasi kata sandi dengan dokumen database
- Jika kata sandi tidak cocok maka bom dan kembalikan kesalahan yang berbeda
- Jika tidak ada kesalahan, ubah kata sandi
- Kemudian kembalikan kesuksesan
- Jika ada yang salah, kembalikan 500
Jadi saat ini tangkapan tampaknya tidak menghentikan rantai, dan itu masuk akal, jadi saya bertanya-tanya apakah ada cara bagi saya untuk memaksa rantai berhenti pada titik tertentu berdasarkan kesalahan, atau jika ada cara yang lebih baik untuk menyusun ini untuk mendapatkan beberapa bentuk perilaku percabangan, seperti halnya kasus if X do Y else Z
.
Bantuan apa pun akan sangat bagus.
javascript
node.js
promise
bluebird
Untung
sumber
sumber
Jawaban:
Perilaku ini persis seperti lemparan sinkron:
Itu setengah dari poin
.catch
- untuk dapat pulih dari kesalahan. Mungkin diinginkan untuk memutar ulang untuk memberi sinyal bahwa status masih error:Namun, ini saja tidak akan berfungsi dalam kasus Anda karena kesalahan ditangkap oleh penangan selanjutnya. Masalah sebenarnya di sini adalah bahwa penanganan kesalahan "HANDLE ANYTHING" yang digeneralisasi adalah praktik yang buruk secara umum dan sangat disukai dalam bahasa dan ekosistem pemrograman lain. Untuk alasan ini Bluebird menawarkan hasil tangkapan dengan tipe dan predikat.
Keuntungan tambahannya adalah logika bisnis Anda tidak (dan tidak seharusnya) harus mengetahui siklus permintaan / respons sama sekali. Ini bukan tanggung jawab kueri untuk memutuskan status dan kesalahan HTTP mana yang didapat klien dan kemudian saat aplikasi Anda berkembang, Anda mungkin ingin memisahkan logika bisnis (cara menanyakan DB Anda dan cara memproses data Anda) dari apa yang Anda kirim ke klien (kode status http apa, teks apa dan tanggapan apa).
Inilah cara saya menulis kode Anda.
Pertama, saya akan
.Query
melemparNoSuchAccountError
, saya akan membuat subkelas darinyaPromise.OperationalError
mana Bluebird sudah menyediakannya. Jika Anda tidak yakin cara membuat subkelas kesalahan, beri tahu saya.Saya juga akan membuat subkelasnya
AuthenticationError
dan kemudian melakukan sesuatu seperti:Seperti yang Anda lihat - ini sangat bersih dan Anda dapat membaca teks seperti instruksi manual tentang apa yang terjadi dalam proses tersebut. Itu juga terpisah dari request / respon.
Sekarang, saya akan menyebutnya dari penangan rute seperti:
Dengan cara ini, logikanya ada di satu tempat dan keputusan tentang cara menangani error ke klien ada di satu tempat dan tidak saling mengacaukan.
sumber
.catch(someSpecificError)
penangan perantara untuk beberapa kesalahan tertentu adalah jika Anda ingin menangkap jenis kesalahan tertentu (yang tidak berbahaya), tangani dan lanjutkan alur yang mengikutinya. Misalnya, saya memiliki beberapa kode startup yang memiliki urutan hal-hal yang harus dilakukan. Hal pertama adalah membaca file konfigurasi dari disk, tetapi jika file konfigurasi itu tidak ada, itu adalah kesalahan OK (program telah dibangun secara default) sehingga saya dapat menangani kesalahan khusus itu dan melanjutkan sisa aliran. Mungkin juga ada pembersihan lebih baik tidak pergi sampai nanti.instanceof
chceks secara manual..catch
berfungsi sepertitry-catch
pernyataan, yang berarti Anda hanya perlu satu tangkapan di akhir:sumber
Tidak. Anda tidak dapat benar-benar "mengakhiri" rantai, kecuali jika Anda membuat pengecualian yang menggelembung sampai akhirnya. Lihat jawaban Benjamin Gruenbaum untuk mengetahui cara melakukannya.
Penurunan polanya bukan untuk membedakan jenis kesalahan, tetapi menggunakan kesalahan yang dimiliki
statusCode
danbody
bidang yang dapat dikirim dari satu.catch
penangan umum . Bergantung pada struktur aplikasi Anda, solusinya mungkin lebih bersih.Ya, Anda dapat melakukan percabangan dengan promise . Namun, ini berarti meninggalkan rantai dan "kembali" ke bersarang - seperti yang Anda lakukan dalam pernyataan bertingkat if-else atau coba-tangkap:
sumber
Saya telah melakukan cara ini:
Anda meninggalkan tangkapan Anda pada akhirnya. Dan lemparkan saja kesalahan saat terjadi di tengah-tengah rantai Anda.
Fungsi Anda yang lain mungkin akan terlihat seperti ini:
sumber
Mungkin agak terlambat ke pesta, tapi mungkin saja bersarang
.catch
seperti yang ditunjukkan di sini:Jaringan Pengembang Mozilla - Menggunakan Janji
Sunting: Saya mengirimkan ini karena menyediakan fungsionalitas yang diminta secara umum. Namun tidak dalam kasus khusus ini. Karena seperti yang sudah dijelaskan secara rinci oleh orang lain,
.catch
seharusnya memulihkan kesalahan. Anda tidak dapat, misalnya, mengirim respons ke klien dalam beberapa.catch
callback karena a.catch
with no eksplisitreturn
menyelesaikannya denganundefined
dalam kasus itu, menyebabkan proses.then
dipicu meskipun rantai Anda tidak benar-benar terselesaikan, berpotensi menyebabkan yang berikut ini.catch
memicu dan mengirim respons lain kepada klien, menyebabkan kesalahan dan kemungkinan besar akan menggangguUnhandledPromiseRejection
Anda. Saya harap kalimat yang berbelit-belit ini masuk akal bagi Anda.sumber
Sebaliknya
.then().catch()...
Anda bisa melakukannya.then(resolveFunc, rejectFunc)
. Rantai janji ini akan lebih baik jika Anda menangani berbagai hal di sepanjang jalan. Inilah cara saya menulis ulang:Catatan: Ini
if (error != null)
adalah sedikit retasan untuk berinteraksi dengan kesalahan terbaru.sumber
Saya pikir jawaban Benjamin Gruenbaum di atas adalah solusi terbaik untuk rangkaian logika yang kompleks, tetapi berikut adalah alternatif saya untuk situasi yang lebih sederhana. Saya hanya menggunakan sebuah
errorEncountered
bendera bersama denganreturn Promise.reject()
untuk melewati pernyataanthen
atau berikutnyacatch
. Jadi akan terlihat seperti ini:Jika Anda memiliki lebih dari dua pasang maka / tangkap, Anda mungkin harus menggunakan solusi Benjamin Gruenbaum. Tapi ini berfungsi untuk pengaturan sederhana.
Perhatikan bahwa final
catch
hanya memilikireturn;
daripadareturn Promise.reject();
, karena tidak ada yang berikutnyathen
yang perlu kita lewati, dan itu akan dihitung sebagai penolakan Promise yang tidak tertangani, yang tidak disukai Node. Seperti yang tertulis di atas, finalcatch
akan mengembalikan Janji yang diselesaikan dengan damai.sumber