Mengapa saya tidak bisa begitu saja melempar Error
panggilan balik tangkapan dan membiarkan proses menangani kesalahan seolah-olah itu dalam lingkup lain?
Jika saya tidak melakukan console.log(err)
apa-apa akan dicetak dan saya tidak tahu apa-apa tentang apa yang terjadi. Prosesnya baru saja berakhir ...
Contoh:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
Jika panggilan balik dieksekusi di utas utama, mengapa Error
penelepon ditelan oleh lubang hitam?
javascript
asynchronous
promise
throw
es6-promise
demian85
sumber
sumber
.catch(…)
kembali..catch((e) => { throw new Error() })
, menulis.catch((e) => { return Promise.reject(new Error()) })
atau hanya.catch((e) => Promise.reject(new Error()))
Jawaban:
Seperti yang orang lain jelaskan, "lubang hitam" adalah karena melempar ke
.catch
dalam rantai yang berlanjut dengan janji yang ditolak, dan Anda tidak memiliki tangkapan lagi, yang mengarah ke rantai yang tidak tertembus, yang menelan kesalahan (buruk!)Tambahkan satu tangkapan lagi untuk melihat apa yang terjadi:
Tangkapan di tengah rantai berguna ketika Anda ingin rantai melanjutkan meskipun langkah gagal, tetapi melempar kembali berguna untuk terus gagal setelah melakukan hal-hal seperti logging informasi atau langkah pembersihan, bahkan mungkin mengubah kesalahan mana terlempar.
Menipu
Untuk membuat kesalahan muncul sebagai kesalahan di konsol web, seperti yang Anda maksudkan pada awalnya, saya menggunakan trik ini:
Bahkan nomor baris tetap ada, jadi tautan di konsol web membawa saya langsung ke file dan baris tempat kesalahan (asli) terjadi.
Mengapa ini berhasil?
Pengecualian dalam fungsi yang disebut sebagai pemenuhan janji atau penangan penolakan akan secara otomatis dikonversi menjadi penolakan atas janji yang seharusnya Anda kembalikan. Kode janji yang menyebut fungsi Anda menangani hal ini.
Fungsi yang disebut oleh setTimeout di sisi lain, selalu berjalan dari kondisi stabil JavaScript, yaitu berjalan dalam siklus baru di loop acara JavaScript. Pengecualian ada tidak tertangkap oleh apa pun, dan membuatnya ke konsol web. Karena
err
menyimpan semua informasi tentang kesalahan, termasuk tumpukan asli, file dan nomor baris, masih dilaporkan dengan benar.sumber
function logErrors(e){console.error(e)}
lalu gunakan sepertido1().then(do2).catch(logErrors)
. Jawabannya sendiri bagus, +1window.onerror
event handler. Hanya dengan melakukansetTimeout
trik ini dapat dilakukan. Kalau tidak, tidakwindow.onerror
akan pernah mendengar apa pun tentang kesalahan yang terjadi di Janji.console.log
ataupostErrorToServer
, Anda bisa melakukan apa yang perlu dilakukan. Tidak ada alasan kode apa pun yang ada diwindow.onerror
dalamnya tidak dapat difaktorkan ke dalam fungsi terpisah dan dipanggil dari 2 tempat. Mungkin lebih pendek darisetTimeout
garis.Hal-hal penting untuk dipahami di sini
Baik
then
dancatch
fungsi mengembalikan objek janji baru.Entah melempar atau menolak secara eksplisit, akan memindahkan janji saat ini ke negara yang ditolak.
Karena
then
dancatch
mengembalikan objek janji baru, mereka dapat dirantai.Jika Anda melempar atau menolak di dalam handler janji (
then
ataucatch
), itu akan ditangani di handler penolakan berikutnya di jalur rantai.Seperti yang disebutkan oleh jfriend00,
then
dancatch
penangan tidak dieksekusi secara bersamaan. Ketika pawang melempar, itu akan segera berakhir. Jadi, tumpukan akan dibatalkan dan pengecualian akan hilang. Itu sebabnya melempar pengecualian menolak janji saat ini.Dalam kasus Anda, Anda menolak di dalam
do1
dengan melemparError
objek. Sekarang, janji saat ini akan dalam keadaan ditolak dan kontrol akan ditransfer ke penangan berikutnya, yangthen
dalam kasus kami.Karena
then
handler tidak memiliki handler penolakan, maka handlerdo2
tidak akan dieksekusi sama sekali. Anda dapat mengkonfirmasi ini dengan menggunakanconsole.log
di dalamnya. Karena janji saat ini tidak memiliki penangan penolakan, itu juga akan ditolak dengan nilai penolakan dari janji sebelumnya dan kontrol akan ditransfer ke penangan berikutnya yangcatch
.Seperti
catch
penangan penolakan, ketika Anda melakukannyaconsole.log(err.stack);
di dalamnya, Anda dapat melihat jejak tumpukan kesalahan. Sekarang, Anda melemparError
objek dari itu sehingga janji yang dikembalikan olehcatch
juga akan dalam keadaan ditolak.Karena Anda belum memasang penangan penolakan apa pun pada
catch
, Anda tidak dapat mengamati penolakan tersebut.Anda dapat membagi rantai dan memahami ini dengan lebih baik, seperti ini
Output yang akan Anda dapatkan akan seperti
Di dalam
catch
handler 1, Anda mendapatkan nilaipromise
objek sebagai ditolak.Cara yang sama, janji yang dikembalikan oleh
catch
pawang 1, juga ditolak dengan kesalahan yang sama dengan yangpromise
ditolak dan kami mengamatinya dicatch
pawang kedua .sumber
.then()
penangan adalah async (tumpukan dibatalkan sebelum dieksekusi) sehingga pengecualian di dalamnya harus diubah menjadi penolakan, jika tidak akan ada penangan pengecualian untuk menangkapnya.Saya mencoba
setTimeout()
metode yang dijelaskan di atas ...Mengganggu, saya menemukan ini benar-benar tidak dapat diuji. Karena itu melempar kesalahan asinkron, Anda tidak dapat membungkusnya di dalam
try/catch
pernyataan, karenacatch
akan berhenti mendengarkan pada saat kesalahan dilemparkan.Saya kembali ke hanya menggunakan pendengar yang bekerja dengan sempurna dan, karena itu JavaScript harus digunakan, sangat dapat diuji.
sumber
Menurut spec (lihat 3.III.d) :
Itu berarti bahwa jika Anda melempar pengecualian dalam
then
fungsi, itu akan ditangkap dan janji Anda akan ditolak.catch
tidak masuk akal di sini, itu hanya jalan pintas ke.then(null, function() {})
Saya kira Anda ingin mencatat penolakan yang tidak ditangani dalam kode Anda. Kebanyakan perpustakaan menjanjikan api
unhandledRejection
untuk itu. Inilah intisari yang relevan dengan diskusi tentangnya.sumber
unhandledRejection
pengait adalah untuk JavaScript sisi server, di sisi klien, peramban yang berbeda memiliki solusi yang berbeda. KAMI belum menstandarkannya tetapi sudah sampai di sana perlahan tapi pasti.Saya tahu ini agak terlambat, tetapi saya menemukan utas ini, dan tidak ada solusi yang mudah diimplementasikan untuk saya, jadi saya membuat sendiri:
Saya menambahkan fungsi pembantu kecil yang mengembalikan janji, seperti:
Kemudian, jika saya memiliki tempat tertentu di rantai janji saya di mana saya ingin melemparkan kesalahan (dan menolak janji), saya hanya kembali dari fungsi di atas dengan kesalahan yang saya buat, seperti:
Dengan cara ini saya bisa mengendalikan kesalahan tambahan dari dalam rantai janji. Jika Anda ingin juga menangani kesalahan janji 'normal', Anda akan memperluas tangkapan Anda untuk memperlakukan kesalahan 'dilempar sendiri' secara terpisah.
Semoga ini bisa membantu, ini adalah jawaban stackoverflow pertama saya!
sumber
Promise.reject(error)
alih-alihnew Promise(function (resolve, reject){ reject(error) })
(yang tetap membutuhkan pernyataan pengembalian)Ya menjanjikan kesalahan menelan, dan Anda hanya bisa menangkapnya
.catch
, seperti yang dijelaskan lebih detail dalam jawaban lain. Jika Anda berada di Node.js dan ingin mereproduksithrow
perilaku normal , mencetak jejak tumpukan ke konsol dan keluar dari proses, Anda dapat melakukansumber
unhandledRejection
acara