Promise catch'te yeniden atma hatası


93

Bir öğreticide aşağıdaki kodu buldum:

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

Biraz kafam karıştı: yakalama çağrısı bir şey başarır mı? Bana öyle geliyor ki, yakalanan aynı hatayı attığı için herhangi bir etkisi yok. Bunu, normal bir deneme / yakalama işleminin nasıl çalıştığına dayandırıyorum.


Eğiticiye bir bağlantı verebilir misiniz? Belki yardımcı olacak ek bağlam vardır ...
Igor

@Igor yapamam, Pluralsight'ta. Bu muhtemelen bazı hata işleme mantığı için bir yer tutucu mu?
Tyler Durden

Daha sonra hiçbir şey yapmadığı için tahmin ettiğim şey budur, sonra hatayı arayana iletir, bu da başlangıçta yakalama olmamasıyla da başarılabilir.
Igor

1
@TylerDurden Yer tutucu olduğu konusunda haklı olduğunuzdan şüpheleniyorum.
Jared Smith

@TylerDurden, bunun bir yer tutucu olduğunu da tahmin ediyorum. Hataların nasıl biçimlendirileceğini / normalleştirileceğini göstermeye çalışıyor olabilir. Temelde vaat-eşdeğeri try { ... }catch(error){ throw new Error("something went wrong") }. Veya Sözler ve Hataların uyumlu olduğunu göstermek için (en azından bu şekilde) . Ancak mevcut uygulamasında bu sadece aptalca. Haklısın, hiçbir şey yapmıyor ve bir kalıtımsal sınıfta üzerine yazmayı etkinleştirmek için OOP'ye ekleyeceğiniz bir kanca bile değil. Yakalama bloğunu bir şey yapar yapmaz eklerdim, ama öyle değil, sadece bir yer tutucu olarak değil.
Thomas

Yanıtlar:


130

Gösterdiğiniz gibi çıplak bir yakalayıp fırlatmanın bir anlamı yok. Kod ekleme ve yavaş yürütme dışında yararlı bir şey yapmaz. Öyleyse, .catch()atacak ve yeniden atacaksan, içinde yapmak istediğin bir şey olmalı .catch(), yoksa sadece .catch()tamamen kaldırmalısın .

Bu genel yapı için olağan nokta .catch(), hatayı günlüğe kaydetme veya bazı durumu temizleme (dosyaları kapatma gibi) gibi bir şeyi yürütmek , ancak söz zincirinin reddedilmiş olarak devam etmesini istemenizdir.

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

Bir öğreticide, insanlara hataları nerede yakalayabileceklerini göstermek veya hatayı ele alıp sonra yeniden atma kavramını öğretmek için orada olabilir.


Yakalama ve yeniden fırlatma için faydalı nedenlerden bazıları şunlardır:

  1. Hatayı günlüğe kaydetmek , ancak söz zincirini reddedilmiş olarak tutmak istiyorsunuz .
  2. Hatayı başka bir hataya dönüştürmek istiyorsunuz (genellikle zincirin sonunda daha kolay hata işleme için). Bu durumda, farklı bir hatayı yeniden atarsınız.
  3. Söz zinciri devam etmeden önce bir dizi işlem yapmak istersiniz (kapat / ücretsiz kaynaklar gibi), ancak söz zincirinin reddedilmiş kalmasını istersiniz.
  4. Bir başarısızlık varsa söz zincirinin bu noktasında hata ayıklayıcı için bir kesme noktası yerleştirmek için bir nokta istiyorsunuz .

Ancak, catch işleyicisinde başka kod olmadan aynı hatanın düz bir şekilde yakalanması ve yeniden atılması, kodun normal çalışması için yararlı hiçbir şey yapmaz.


Bence bu iyi bir örnek değil. Bu tür bir yaklaşımla, 1 hata için birden fazla günlük kaydı elde edersiniz. Java'da throw new Exception(periousException);javascript'in iç içe geçmiş hatayı destekleyip desteklemediğini bilmiyorum ama yine de "log and throw" kötü bir uygulamadır.
Cherry

27
@Cherry - Bunun genel olarak kötü bir uygulama olduğunu söyleyemezsiniz. Bir modülün kendi hatalarını kendi yöntemiyle günlüğe kaydetmek istediği zamanlar vardır ve bu, bunu yapmanın bir yoludur. Ben bu tavsiye değilim yanında, sadece için hiçbir neden yok olduğunu açıklayan ediyorum .catch()ve başka bir şey yapmak sürece catch içinde aynı hatayı atmak .catch(). Bu cevabın amacı bu.
jfriend00

Genel olarak istisnalar soyutlama seviyesine uymalıdır. Örneğin db ile ilgili bir istisnayı yakalamak ve arayan tarafından ele alınacak bir "servis" istisnası gibi bir şey atmak tamamen tamamdır. Bu özellikle düşük seviyeli istisnalarla ilgili ayrıntıları ifşa etmediğinizde kullanışlıdır
maxTrialfire

3
Yakalamak ve (bazen) fırlatmak için başka bir iyi neden, belirli bir hatayı ele almak, ancak diğer her şeyi yeniden atmaktır.
Jasper

2
@SimonZyx - Evet, .finally()bunun için çok yararlı olabilir, ancak bazen kaynaklar zaten hatasız yolda halledilir, bu yüzden .catch()onları kapatmanın yeri yine de olur. Gerçekten duruma bağlı.
jfriend00

16

Hem .then()ve hem de .catch()yöntemler Promises'i döndürür ve herhangi bir işleyicide bir İstisna atarsanız, döndürülen söz reddedilir ve İstisna, bir sonraki reddetme işleyicisinde yakalanır.

Aşağıdaki kodda, .catch()ikinciye yakalanan birinciye bir istisna atıyoruz .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);
});

İkincisi .catch(), yerine getirilen bir Söz Verildi, .then()işleyici çağrılabilir:

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');
});

Yararlı başvuru: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Bu yardımcı olur umarım!


4

catchYöntem çağrısını tamamen devre dışı bırakırsanız önemli bir fark yoktur .

Eklediği tek şey fazladan bir mikro görevdir, bu da pratikte sözün reddini catchmadde olmadan başarısız olan bir sözden daha sonra fark edeceğiniz anlamına gelir .

Bir sonraki kod parçası bunu göstermektedir:

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) );

İkinci reddin ilkinden önce nasıl rapor edildiğine dikkat edin. Tek fark bu.


3

Öyleyse, sorunuza benziyor, "Söz zincirinde, .catch()yöntem ne işe yarar?"

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

Throw ifadesi "duracaktır (atmadan sonraki ifadeler çalıştırılmayacaktır) ve kontrol, çağrı yığınındaki ilk yakalama bloğuna geçirilecektir. Arayan işlevleri arasında yakalama bloğu yoksa, program sona erecektir."

Söz zincirinde, .then()yöntem bir tür veri parçası döndürecektir. Yığınların bu dönüşü vaadi tamamlayacak. Verilerin başarılı bir şekilde geri döndürülmesi sözü tamamlar. .catch()Yöntemi de aynı şekilde düşünebilirsiniz . .catch()ancak başarısız veri alımlarını idare edecektir. Fırlatma ifadesi sözü tamamlar. Zaman zaman, geliştiricilerin .catch((err) => {console.log(err))} söz zincirini tamamlayacak olanı kullandığını göreceksiniz .


0

Aslında onu yeniden atmanıza gerek yok, sadece Promise.catch'i boş bırakın, aksi takdirde reddetmeyi kaldırmış olarak kabul edecek ve sonra kodu bir try catch'e saracak ve aktarılan hatayı otomatik olarak yakalayacaktır.

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
}

0

Söz zincirinde .catch kullanmak daha iyidir

ex fonksiyonunda f2: .sonra (...). catch (e => reddet (e));

  • test1 - try catch ile
  • test2 - try veya .catch olmadan
  • test3 - .catch ile

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);

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.