Ripetizione dell'errore nella cattura della promessa


93

Ho trovato il seguente codice in un tutorial:

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

Sono un po 'confuso: il richiamo ha qualcosa? Mi sembra che non abbia alcun effetto, poiché genera semplicemente lo stesso errore che è stato catturato. Baso questo su come funziona un try / catch regolare.


Potresti fornire un collegamento al tutorial? Forse c'è un contesto aggiuntivo che sarebbe utile ...
Igor

@ Igor Non posso, è su Pluralsight. Questo è forse solo un segnaposto per una logica di gestione degli errori?
Tyler Durden

Questo è quello che immagino poiché non fa altro che passare l'errore al chiamante che potrebbe anche essere ottenuto non avendo il trucco per cominciare.
Igor

1
@TylerDurden Sospetto che tu abbia ragione sul fatto che sia un segnaposto.
Jared Smith

@TylerDurden, immagino anche che sia un segnaposto. Forse provando a dimostrare come formattare / normalizzare gli errori. Fondamentalmente la promessa equivalente a try { ... }catch(error){ throw new Error("something went wrong") }. O per mostrare che le promesse e gli errori sono compatibili (almeno in questo modo) . Ma nella sua attuale implementazione è semplicemente stupido. Hai ragione, non fa nulla e non è nemmeno come un hook che aggiungi in OOP per abilitare la sovrascrittura in una classe che eredita. Aggiungerei il blocco di cattura non appena fa qualcosa, ma non così, non solo come segnaposto.
Thomas,

Risposte:


130

Non ha senso prendere e lanciare nudi mentre mostri. Non fa nulla di utile tranne che aggiungere codice e l'esecuzione lenta. Quindi, se hai intenzione di .catch()rilanciare, dovrebbe esserci qualcosa che vuoi fare in .catch(), altrimenti dovresti semplicemente rimuovere .catch()completamente.

Il punto normale per quella struttura generale è quando si desidera eseguire qualcosa .catch()come registrare l'errore o ripulire uno stato (come i file chiusi), ma si desidera che la catena di promesse continui come rifiutata.

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

In un tutorial, potrebbe essere lì solo per mostrare alle persone dove possono rilevare gli errori o per insegnare il concetto di gestire l'errore, quindi rilanciarlo.


Alcuni dei motivi utili per la cattura e il rilancio sono i seguenti:

  1. Si desidera registrare l'errore , ma mantenere la catena di promesse rifiutata.
  2. Volete trasformare l'errore in qualche altro errore (spesso per una più facile elaborazione degli errori alla fine della catena). In questo caso, rilanceresti un errore diverso.
  3. Si desidera eseguire un po 'di elaborazione prima che la catena di promesse continui (come risorse chiuse / libere) ma si desidera che la catena di promesse rimanga rifiutata.
  4. Si desidera un punto in cui inserire un punto di interruzione per il debugger a questo punto della catena di promesse se si verifica un errore.

Tuttavia, una semplice cattura e rilancio dello stesso errore senza altro codice nel gestore di cattura non fa nulla di utile per il normale funzionamento del codice.


A mio parere non è un buon esempio. Con tale approccio è possibile ottenere facilmente più registrazioni per 1 errore. In java puoi semplicemente throw new Exception(periousException);non so se javascript supporta errori nidificati, ma comunque "log and throw" è una cattiva pratica.
Cherry,

27
@ Cherry - Non puoi dire che questa sia una cattiva pratica in generale. Ci sono momenti in cui un modulo vuole registrare i propri errori a modo suo e questo è un modo per farlo. Inoltre, non lo sto raccomandando, sto solo spiegando che non c'è motivo di avere un .catch()e lanciare lo stesso errore all'interno del fermo a meno che tu non faccia QUALCOSA altro nel file .catch(). Questo è il punto di questa risposta.
jfriend00

Generalmente le eccezioni dovrebbero adattarsi al livello di astrazione. È perfettamente OK per catturare un'eccezione relativa al database, ad esempio, e lanciare qualcosa come un'eccezione "servizio" che verrà gestita dal chiamante. Ciò è particolarmente utile quando non si desidera esporre i dettagli sulle eccezioni di basso livello
maxTrialfire

3
Un altro buon motivo per catturare e (a volte) lanciare è gestire un errore specifico, ma rilanciare tutto il resto.
Jasper

2
@SimonZyx - Sì, .finally()può essere molto utile per questo, ma a volte le risorse sono già gestite nel percorso non di errore, quindi .catch()è ancora il posto per chiuderle. Dipende davvero dalla situazione.
jfriend00

16

Sia .then()e .catch()metodi restituiscono promesse, e se un'eccezione sia gestore, la promessa restituita è respinta e l'eccezione saranno catturati nella prossima rifiutano gestore.

Nel codice seguente, viene generata un'eccezione nel primo .catch(), che viene catturata nel secondo .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);
});

Il secondo .catch()restituisce una Promessa soddisfatta, il .then()gestore può essere chiamato:

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

Riferimento utile: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Spero che sia di aiuto!


4

Non c'è differenza importante se si tralascia completamente la catchchiamata al metodo.

L'unica cosa che aggiunge è una microtask extra, che in pratica significa che noterai il rifiuto della promessa più tardi di quanto non sia il caso di una promessa che fallisce senza la catchclausola.

Lo snippet successivo lo dimostra:

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

Nota come il secondo rifiuto viene segnalato prima del primo. Questa è l'unica differenza.


3

Quindi sembra che la tua domanda sia: "Nella catena delle promesse, cosa fa il .catch()metodo?"

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

L'istruzione throw "si fermerà (le istruzioni dopo throw non verranno eseguite) e il controllo verrà passato al primo blocco catch nello stack di chiamate. Se non esiste alcun blocco catch tra le funzioni del chiamante, il programma terminerà."

Nella catena delle promesse, il .then()metodo restituirà un tipo di blocco di dati. Questo ritorno del pezzo completerà la promessa. La corretta restituzione dei dati completa la promessa. Puoi pensare al .catch()metodo allo stesso modo. .catch()tuttavia gestirà i recuperi di dati non riusciti. L'istruzione throw completa la promessa. Occasionalmente, vedrai l'uso da parte degli sviluppatori .catch((err) => {console.log(err))} che completerebbe anche la catena di promesse.


0

In realtà non è necessario rilanciarlo, basta lasciare vuoto Promise.catch altrimenti considererà come non gestire il rifiuto e quindi avvolgere il codice in un tentativo di cattura e catturerà automaticamente l'errore che viene trasmesso.

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

Nella catena delle promesse, è meglio usare .catch

ex nella funzione f2: .then (...). catch (e => respinge (e));

  • test1 - con try catch
  • test2 - senza try o .catch
  • test3 - con .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);

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.