Erreur de relance dans la capture de promesse

88

J'ai trouvé le code suivant dans un tutoriel:

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

Je suis un peu confus: l'appel catch a-t-il quelque chose à faire? Il me semble que cela n'a aucun effet, car il renvoie simplement la même erreur qui a été détectée. Je base cela sur le fonctionnement d'un essai / capture régulier.

Tyler Durden
la source
Pouvez-vous fournir un lien vers le didacticiel? Peut-être qu'il y a un contexte supplémentaire qui serait utile ...
Igor
@Igor je ne peux pas, c'est sur Pluralsight. Est-ce peut-être juste un espace réservé pour une logique de traitement des erreurs?
Tyler Durden
C'est ce que je suppose, car il ne fait rien de plus que de transmettre l'erreur à l'appelant, ce qui pourrait également être accompli en n'ayant pas la capture pour commencer.
Igor
1
@TylerDurden Je soupçonne que vous avez raison de dire qu'il s'agit d'un espace réservé.
Jared Smith
@TylerDurden, je suppose également que c'est un espace réservé. Peut-être essayer de montrer comment formater / normaliser les erreurs. Fondamentalement, l'équivalent de la promesse try { ... }catch(error){ throw new Error("something went wrong") }. Ou pour montrer que les promesses et les erreurs sont compatibles (du moins de cette façon) . Mais dans sa mise en œuvre actuelle, c'est tout simplement stupide. Vous avez raison, cela ne fait rien et ce n'est même pas comme un hook que vous ajouteriez dans la POO pour permettre de l'écraser dans une classe héritière. J'ajouterais le bloc catch dès qu'il fait quelque chose, mais pas comme ça, pas seulement comme espace réservé.
Thomas

Réponses:

124

Il ne sert à rien de prendre et lancer nus comme vous le montrez. Il ne fait rien d'utile sauf ajouter du code et ralentir l'exécution. Donc, si vous voulez .catch()relancer, il devrait y avoir quelque chose que vous voulez faire dans le .catch(), sinon vous devriez simplement supprimer .catch()complètement le.

Le point habituel de cette structure générale est lorsque vous voulez exécuter quelque chose dans le .catch()tel que consigner l'erreur ou nettoyer un état (comme fermer des fichiers), mais que vous voulez que la chaîne de promesses continue comme rejetée.

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

Dans un didacticiel, il peut être là simplement pour montrer aux gens où ils peuvent détecter des erreurs ou pour enseigner le concept de gestion de l'erreur, puis la renvoyer.


Certaines des raisons utiles pour attraper et relancer sont les suivantes:

  1. Vous souhaitez consigner l'erreur , mais gardez la chaîne de promesse comme rejetée.
  2. Vous voulez transformer l'erreur en une autre erreur (souvent pour faciliter le traitement des erreurs à la fin de la chaîne). Dans ce cas, vous renverriez une erreur différente.
  3. Vous souhaitez effectuer un certain nombre de traitements avant que la chaîne de promesse ne se poursuive (par exemple, fermer / libérer des ressources), mais vous voulez que la chaîne de promesse reste rejetée.
  4. Vous voulez un emplacement pour placer un point d'arrêt pour le débogueur à ce stade de la chaîne de promesse en cas d'échec.

Mais, une simple capture et relance de la même erreur sans autre code dans le gestionnaire de capture ne fait rien d'utile pour l'exécution normale du code.

jfriend00
la source
À mon avis, ce n’est pas un bon exemple. Avec une telle approche, vous obtenez facilement une journalisation multiple pour 1 erreur. En java, throw new Exception(periousException);je ne sais pas si javascript prend en charge les erreurs imbriquées, mais de toute façon "log and throw" est une mauvaise pratique.
Cherry
26
@Cherry - Vous ne pouvez pas dire que c'est une mauvaise pratique en général. Il y a des moments où un module veut enregistrer ses propres erreurs à sa manière et c'est une façon de le faire. De plus, je ne recommande pas cela, j'explique simplement qu'il n'y a aucune raison d'avoir un .catch()et de lancer la même erreur dans la capture à moins que vous ne fassiez QUELQUE CHOSE d'autre dans le .catch(). C'est le but de cette réponse.
jfriend00 du
En général, les exceptions doivent correspondre au niveau d'abstraction. C'est parfaitement OK pour attraper une exception liée à la base de données par exemple, et lancer quelque chose comme une exception "service" qui sera gérée par l'appelant. Ceci est particulièrement utile lorsque vous ne savez pas quoi exposer des détails sur les exceptions de bas niveau
maxTrialfire
3
Une autre bonne raison d'attraper et (parfois) de lancer est de gérer une erreur spécifique, mais de relancer tout le reste.
Jasper
2
@SimonZyx - Oui, cela .finally()peut être très utile pour cela, mais parfois les ressources sont déjà prises en charge dans le chemin sans erreur, c'est donc .catch()toujours l'endroit pour les fermer. Cela dépend vraiment de la situation.
jfriend00
15

Les méthodes .then()et .catch()renvoient des promesses, et si vous lancez une exception dans l'un ou l'autre des gestionnaires, la promesse renvoyée est rejetée et l'exception sera interceptée dans le prochain gestionnaire de rejet.

Dans le code suivant, nous lançons une exception dans le premier .catch(), qui est intercepté dans le second .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);
});

Le second .catch()retourne un Promised qui est rempli, le .then()gestionnaire peut être appelé:

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

Référence utile: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

J'espère que cela t'aides!

Philippe Sultan
la source
4

Il n'y a pas de différence importante si vous omettez le catch appel de méthode.

La seule chose qu'il ajoute est une microtâche supplémentaire, ce qui signifie en pratique que vous remarquerez le rejet de la promesse plus tard que ce n'est le cas pour une promesse qui échoue sans la catchclause.

L'extrait suivant montre ceci:

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

Notez comment le deuxième rejet est signalé avant le premier. C'est à peu près la seule différence.

trincot
la source
3

Donc, il semble que votre question soit: "Dans la chaîne de promesses, que fait la .catch()méthode?"

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

L'instruction throw "s'arrêtera (les instructions après throw ne seront pas exécutées), et le contrôle sera passé au premier bloc catch de la pile d'appels. Si aucun bloc catch n'existe parmi les fonctions appelantes, le programme se terminera."

Dans la chaîne de promesse, la .then()méthode retournera un type de bloc de données. Ce retour du morceau complètera la promesse. Le retour réussi des données complète la promesse. Vous pouvez penser à la .catch()méthode de la même manière. .catch()cependant traitera les récupérations de données infructueuses. L'instruction throw complète la promesse. Parfois, vous verrez des développeurs utiliser .catch((err) => {console.log(err))} ce qui compléterait également la chaîne de promesses.

Matt Fernandez
la source
0

En fait, vous n'avez pas besoin de le relancer, laissez simplement le Promise.catch vide, sinon il considérera comme non gérer le rejet, puis encapsulera le code dans un try catch et il attrapera automatiquement l'erreur qui est transmise.

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
la source
0

Dans la chaîne de promesses, il est préférable d'utiliser .catch

ex dans la fonction f2: .then (...). catch (e => rejeter (e));

  • test1 - avec try catch
  • test2 - sans try ni .catch
  • test3 - avec .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
la source