Kesalahan mengembangkan kembali dalam tangkapan janji

93

Saya menemukan kode berikut dalam tutorial:

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

Saya agak bingung: apakah panggilan tangkap mencapai sesuatu? Tampaknya bagi saya itu tidak berpengaruh apa-apa, karena itu hanya melempar kesalahan yang sama yang tertangkap. Saya mendasarkan ini pada cara kerja coba / tangkap biasa.

Tyler Durden
sumber
Bisakah Anda memberikan tautan ke tutorial? Mungkin ada konteks tambahan yang akan membantu ...
Igor
@Igor Aku tidak bisa, ada di Pluralsight. Apakah ini mungkin hanya placeholder untuk beberapa kesalahan penanganan logika?
Tyler Durden
Itulah yang akan saya tebak karena tidak lebih dari itu meneruskan kesalahan kepada pemanggil yang juga dapat dilakukan dengan tidak memiliki tangkapan untuk memulai.
Igor
1
@TylerDurden Saya curiga Anda benar tentang hal itu sebagai placeholder.
Jared Smith
@TylerDurden, saya juga menebak bahwa ini adalah placeholder. Mungkin mencoba mendemonstrasikan cara memformat / menormalkan kesalahan. Pada dasarnya setara dengan janji try { ... }catch(error){ throw new Error("something went wrong") }. Atau untuk menunjukkan bahwa Promises and Errors kompatibel (setidaknya seperti itu) . Tetapi dalam implementasinya saat ini itu hanya bodoh. Anda benar, itu tidak melakukan apa-apa dan itu bahkan tidak seperti pengait yang Anda tambahkan dalam OOP untuk mengaktifkan penimpaan dalam kelas yang mewarisi. Saya akan menambahkan blok tangkap segera setelah melakukan sesuatu, tetapi tidak seperti itu, tidak hanya sebagai placeholder.
Thomas

Jawaban:

130

Tidak ada gunanya menangkap dan melempar telanjang saat Anda tunjukkan. Itu tidak melakukan sesuatu yang berguna kecuali menambahkan kode dan eksekusi lambat. Jadi, jika Anda akan .catch()dan melempar ulang, seharusnya ada sesuatu yang ingin Anda lakukan di .catch(), jika tidak, Anda harus menghapus .catch()seluruhnya.

Poin yang biasa untuk struktur umum tersebut adalah ketika Anda ingin mengeksekusi sesuatu .catch()seperti mencatat kesalahan atau membersihkan beberapa status (seperti file tutup), tetapi Anda ingin rantai janji terus berlanjut saat ditolak.

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});

Dalam tutorial, mungkin ada di sana hanya untuk menunjukkan kepada orang-orang di mana mereka dapat menemukan kesalahan atau untuk mengajarkan konsep penanganan kesalahan, lalu melemparkannya kembali.


Beberapa alasan berguna untuk menangkap dan melempar kembali adalah sebagai berikut:

  1. Anda ingin mencatat error , tetapi tetap mempertahankan rantai janji sebagai ditolak.
  2. Anda ingin mengubah kesalahan menjadi beberapa kesalahan lain (seringkali untuk memudahkan pemrosesan kesalahan di akhir rangkaian). Dalam kasus ini, Anda akan memunculkan kembali kesalahan yang berbeda.
  3. Yang kamu ingin melakukan banyak pemrosesan sebelum rantai janji berlanjut (seperti sumber daya dekat / gratis), tetapi Anda ingin rantai janji tetap ditolak.
  4. Anda ingin tempat untuk menempatkan breakpoint untuk debugger pada titik ini di rantai perjanjian jika terjadi kegagalan.

Namun, tangkapan sederhana dan penelusuran ulang dari kesalahan yang sama tanpa kode lain di penangan tangkapan tidak melakukan apa pun yang berguna untuk menjalankan kode secara normal.

jfriend00
sumber
Menurut pendapat saya, ini bukan contoh yang baik. Dengan pendekatan seperti itu, Anda dengan mudah mendapatkan banyak pencatatan untuk 1 kesalahan. Di java Anda bisa saja throw new Exception(periousException);saya tidak tahu apakah javascript mendukung kesalahan bersarang, tapi bagaimanapun juga "log and throw" adalah praktik yang buruk.
Cherry
27
@Cherry - Anda tidak dapat mengatakan bahwa ini adalah praktik yang buruk secara umum. Ada kalanya modul ingin mencatat kesalahannya sendiri dengan caranya sendiri dan ini adalah salah satu cara untuk melakukannya. Selain itu, saya tidak merekomendasikan ini, saya hanya menjelaskan bahwa tidak ada alasan untuk memiliki .catch()dan melempar kesalahan yang sama di dalam tangkapan kecuali Anda melakukan SESUATU lain di .catch(). Itulah inti dari jawaban ini.
jfriend00
Umumnya pengecualian harus sesuai dengan tingkat abstraksi. Tidak apa-apa untuk menangkap pengecualian terkait db misalnya, dan melempar sesuatu seperti pengecualian "layanan" yang akan ditangani oleh pemanggil. Ini sangat berguna ketika Anda tidak ingin mengungkapkan detail tentang pengecualian tingkat rendah
maxTrialfire
3
Alasan bagus lainnya untuk menangkap dan (terkadang) melempar adalah untuk menangani kesalahan tertentu, tetapi melempar ulang yang lainnya.
Jasper
2
@SimonZyx - Ya, .finally()bisa sangat berguna untuk itu, tetapi terkadang sumber daya sudah ditangani di jalur non-kesalahan sehingga .catch()masih menjadi tempat untuk menutupnya. Itu sangat tergantung pada situasinya.
jfriend00
16

Kedua metode .then()dan .catch()mengembalikan Promises, dan jika Anda melempar Exception di salah satu penangan, janji yang dikembalikan akan ditolak dan Exception akan ditangkap di penangan penolakan berikutnya.

Dalam kode berikut, kami melempar pengecualian di kode pertama .catch(), yang ditangkap di kode kedua .catch():

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});

Yang kedua .catch()mengembalikan Janji yang terpenuhi, .then()pawang bisa dipanggil:

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});

Referensi yang berguna: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Semoga ini membantu!

Philippe Sultan
sumber
4

Tidak ada perbedaan penting jika Anda catchsepenuhnya mengabaikan pemanggilan metode.

Satu-satunya hal yang ditambahkannya adalah microtask ekstra, yang dalam praktiknya berarti Anda akan melihat penolakan dari promise lebih lambat daripada kasus promise yang gagal tanpa catchklausa.

Cuplikan berikutnya menunjukkan ini:

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );

Perhatikan bagaimana penolakan kedua dilaporkan sebelum penolakan pertama. Itulah satu-satunya perbedaan.

trincot
sumber
3

Jadi sepertinya pertanyaan Anda adalah, "Dalam rantai janji, apa fungsi .catch()metode ini?"

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw

Pernyataan lemparan "akan berhenti (pernyataan setelah lemparan tidak akan dijalankan), dan kontrol akan diteruskan ke blok catch pertama dalam tumpukan panggilan. Jika tidak ada blok catch di antara fungsi pemanggil, program akan dihentikan."

Dalam rantai janji, .then()metode ini akan mengembalikan beberapa jenis potongan data. Pengembalian potongan ini akan melengkapi janji. Pengembalian data yang berhasil melengkapi janji tersebut. Anda dapat memikirkan .catch()metode dengan cara yang sama. .catch()namun akan menangani pengambilan data yang tidak berhasil. Pernyataan lemparan melengkapi janji. Terkadang, Anda akan melihat developer menggunakan .catch((err) => {console.log(err))} yang juga akan menyelesaikan rantai perjanjian.

Matt Fernandez
sumber
0

Anda sebenarnya tidak perlu membuangnya kembali, biarkan saja Promise.catch kosong jika tidak maka akan dianggap sebagai un menangani penolakan dan kemudian membungkus kode dalam mencoba menangkap dan itu akan menangkap kesalahan secara otomatis yang lewat.

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}
Aylian Craspa
sumber
0

Dalam rantai janji, lebih baik menggunakan .catch

ex di fungsi f2: .then (...). catch (e => reject (e));

  • test1 - dengan coba tangkap
  • test2 - tanpa try atau .catch
  • test3 - dengan .catch

function f1() {
    return new Promise((resolve, reject) => {
        throw new Error('test');
    });
}

function f2() {
    return new Promise((resolve, reject) => {
        f1().then(value => {
            console.log('f1 ok ???');
        }).catch(e => reject(e));
    });
}

function test1() {
    console.log('test1 - with try catch - look in F12');
    try {
      f2().then(() => { // Uncaught (in promise) Error: test
        console.log('???'); });
    } catch (e) {
      console.log('this error dont catched');
    }
}

function test2() {
    console.log('test2 - without try or .catch - look in F12');
    f2(); // Uncaught (in promise) Error: test
}

function test3() {
  console.log('test3 - with .catch');
  f2().then(value => {
    console.log('??');
  }).catch(e => {
    console.log(' now its ok, error ', e);
  })
}

setTimeout(() => { test1(); 
  setTimeout(() => { test2(); 
    setTimeout(() => { test3(); 
    }, 100);
  }, 100);
}, 100);

Wagner Pereira
sumber