Ponowne wyrzucenie błędu w złowieniu obietnicy


88

W samouczku znalazłem następujący kod:

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

Jestem trochę zdezorientowany: czy połączenie telefoniczne coś daje? Wydaje mi się, że nie ma to żadnego efektu, ponieważ po prostu rzuca ten sam błąd, który został złapany. Opieram się na tym, jak działa zwykły try / catch.


Czy możesz podać link do samouczka? Może jest dodatkowy kontekst, który byłby pomocny ...
Igor

@Igor Nie mogę, jest w Pluralsight. Czy to może być tylko symbol zastępczy dla logiki obsługi błędów?
Tyler Durden,

Zgaduję, że nie robi nic więcej niż przekazuje błąd dzwoniącemu, co można również osiągnąć, nie mając zaczepu na początku.
Igor

1
@TylerDurden Podejrzewam, że masz rację co do tego, że jest to symbol zastępczy.
Jared Smith

@TylerDurden, przypuszczam również, że jest to symbol zastępczy. Może próbując zademonstrować, jak formatować / normalizować błędy. Zasadniczo równoważnik obietnicy try { ... }catch(error){ throw new Error("something went wrong") }. Lub pokazać, że obietnice i błędy są kompatybilne (przynajmniej w ten sposób) . Ale w obecnej realizacji jest to po prostu głupie. Masz rację, nic nie robi i nawet nie przypomina haka, który można dodać w OOP, aby umożliwić nadpisanie go w klasie dziedziczącej. Dodałbym blok catch, gdy tylko coś zrobi, ale nie w ten sposób, nie tylko jako symbol zastępczy.
Thomas,

Odpowiedzi:


124

Jak pokazujesz, nie ma sensu łapanie i rzucanie nago. Nie robi nic użytecznego poza dodawaniem kodu i powolnym wykonywaniem. Tak więc, jeśli zamierzasz .catch()rzucić ponownie, powinno być coś, co chcesz zrobić, w .catch()przeciwnym razie powinieneś po prostu .catch()całkowicie usunąć .

Typowym punktem tej ogólnej struktury jest sytuacja, gdy chcesz wykonać coś w .catch()pliku, na przykład zarejestrować błąd lub wyczyścić jakiś stan (na przykład zamknięte pliki), ale chcesz, aby łańcuch obietnic był kontynuowany jako odrzucony.

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

W samouczku może to być tylko po to, aby pokazać ludziom, gdzie mogą wyłapać błędy lub nauczyć koncepcji obsługi błędu, a następnie ponownie go zgłosić.


Niektóre z przydatnych powodów łapania i ponownego rzucania są następujące:

  1. Chcesz zarejestrować błąd , ale zachować łańcuch obietnic jako odrzucony.
  2. Chcesz przekształcić błąd w inny błąd (często w celu łatwiejszego przetwarzania błędów na końcu łańcucha). W takim przypadku należy ponownie zgłosić inny błąd.
  3. Chcesz wykonać kilka operacji przetwarzania, zanim łańcuch obietnic będzie kontynuowany (na przykład zamknięte / wolne zasoby), ale chcesz, aby łańcuch obietnic pozostał odrzucony.
  4. Potrzebujesz miejsca, w którym umieści punkt przerwania dla debugera w tym punkcie łańcucha obietnic, jeśli wystąpi awaria.

Ale zwykłe przechwycenie i ponowne zgłoszenie tego samego błędu bez żadnego innego kodu w procedurze obsługi catch nie robi nic użytecznego dla normalnego działania kodu.


Moim zdaniem nie jest to dobry przykład. Dzięki takiemu podejściu łatwo uzyskasz wielokrotne logowanie dla 1 błędu. W javie możesz po prostu throw new Exception(periousException);nie wiem, czy javascript obsługuje zagnieżdżone błędy, ale i tak "loguj i wyrzucaj" to zła praktyka.
Cherry

26
@Cherry - Nie można powiedzieć, że jest to ogólnie zła praktyka. Są chwile, kiedy moduł chce rejestrować własne błędy na swój własny sposób i jest to jeden ze sposobów na zrobienie tego. Poza tym nie polecam tego, tylko wyjaśniam, że nie ma powodu, aby mieć .catch()i wrzucać ten sam błąd wewnątrz haczyka, chyba że zrobisz COŚ jeszcze w .catch(). O to chodzi w tej odpowiedzi.
jfriend00

Generalnie wyjątki powinny odpowiadać poziomowi abstrakcji. Można na przykład wyłapać wyjątek związany z bazą danych i wyrzucić coś w rodzaju wyjątku „usługi”, który będzie obsługiwany przez wywołującego. Jest to szczególnie przydatne, gdy nie możesz ujawniać szczegółów dotyczących wyjątków niskiego poziomu
maxTrialfire

3
Innym dobrym powodem, aby złapać i (czasami) rzucić, jest obsłużenie określonego błędu, ale ponowne wrzucenie wszystkiego innego.
Jasper

2
@SimonZyx - Tak, .finally()może być do tego bardzo przydatne, ale czasami zasoby są już obsługiwane w ścieżce bez błędów, więc .catch()nadal jest miejsce, aby je zamknąć. To naprawdę zależy od sytuacji.
jfriend00

15

Obie metody .then()i .catch()metody zwracają Promises, a jeśli wyrzucisz wyjątek w którymkolwiek module obsługi, zwrócona obietnica zostanie odrzucona, a wyjątek zostanie przechwycony w następnym programie obsługi odrzucenia.

W poniższym kodzie rzucamy wyjątek w pierwszym .catch(), który jest przechwytywany w drugim .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);
});

Drugi .catch()zwraca Obietnicę, która jest spełniona, .then()procedura obsługi może być wywołana:

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

Przydatne źródła: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Mam nadzieję że to pomoże!


4

Nie ma istotnej różnicy, jeśli catchcałkowicie pominiesz wywołanie metody.

Jedyne, co dodaje, to dodatkowe mikrozadanie, co w praktyce oznacza, że ​​odrzucenie obietnicy zauważysz później niż w przypadku obietnicy, która nie powiedzie się bez catchklauzuli.

Pokazuje to następny fragment kodu:

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

Zwróć uwagę, jak drugie odrzucenie jest zgłaszane przed pierwszym. To jedyna różnica.


3

Wygląda więc na to, że twoje pytanie brzmi: „W łańcuchu obietnic, co robi ta .catch()metoda?”

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

Instrukcja throw „zatrzyma się (instrukcje po throw nie zostaną wykonane), a sterowanie zostanie przekazane do pierwszego bloku catch na stosie wywołań. Jeśli wśród funkcji wywołujących nie ma bloku catch, program zakończy działanie”.

W łańcuchu obietnic .then()metoda zwróci pewien typ fragmentu danych. Ten zwrot fragmentu dopełni obietnicę. Pomyślny zwrot danych dopełnia obietnicy. Możesz myśleć o .catch()metodzie w ten sam sposób. .catch()jednak poradzi sobie z nieudanym pobieraniem danych. Instrukcja throw dopełnia obietnicę. Od czasu do czasu zobaczysz, jak deweloperzy używają, .catch((err) => {console.log(err))} co również uzupełniłoby łańcuch obietnic.


0

W rzeczywistości nie musisz go ponownie rzucać, po prostu zostaw Promise.catch pusty, w przeciwnym razie uzna, że ​​nie obsłuży odrzucenia, a następnie zawinie kod w try catch i automatycznie złapie błąd, który jest przekazywany.

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

W łańcuchu obietnic lepiej jest użyć .catch

ex w funkcji f2 :. to (...). catch (e => odrzuc (e));

  • test1 - z try catch
  • test2 - bez try lub .catch
  • test3 - z .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);

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.