Pourquoi ne puis-je pas simplement lancer un Error
rappel à l'intérieur du catch et laisser le processus gérer l'erreur comme si elle était dans une autre portée?
Si je ne fais console.log(err)
rien, rien n'est imprimé et je ne sais rien de ce qui s'est passé. Le processus se termine juste ...
Exemple:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
Si les rappels sont exécutés dans le thread principal, pourquoi Error
est-il avalé par un trou noir?
javascript
asynchronous
promise
throw
es6-promise
demian85
la source
la source
.catch(…)
revient..catch((e) => { throw new Error() })
, écrivez.catch((e) => { return Promise.reject(new Error()) })
ou simplement.catch((e) => Promise.reject(new Error()))
Réponses:
Comme d'autres l'ont expliqué, le "trou noir" est parce que jeter à l'intérieur d'un
.catch
continue la chaîne avec une promesse rejetée, et vous n'avez plus de prises, conduisant à une chaîne inachevée, qui avale les erreurs (mauvais!)Ajoutez une autre capture pour voir ce qui se passe:
Une prise au milieu d'une chaîne est utile lorsque vous voulez que la chaîne continue malgré une étape échouée, mais une relance est utile pour continuer à échouer après avoir fait des choses comme la journalisation d'informations ou les étapes de nettoyage, peut-être même en modifiant l'erreur. Est lancé.
Tour
Pour que l'erreur s'affiche comme une erreur dans la console Web, comme vous l'aviez initialement prévu, j'utilise cette astuce:
Même les numéros de ligne survivent, donc le lien dans la console Web m'amène directement au fichier et à la ligne où l'erreur (d'origine) s'est produite.
Pourquoi ça marche
Toute exception dans une fonction appelée comme gestionnaire de traitement de promesse ou de rejet est automatiquement convertie en un rejet de la promesse que vous êtes censé renvoyer. Le code de promesse qui appelle votre fonction s'en charge.
Une fonction appelée par setTimeout en revanche, fonctionne toujours à partir de l'état stable JavaScript, c'est-à-dire qu'elle s'exécute dans un nouveau cycle dans la boucle d'événements JavaScript. Les exceptions là-bas ne sont détectées par rien et parviennent à la console Web. Puisque
err
contient toutes les informations sur l'erreur, y compris la pile d'origine, le fichier et le numéro de ligne, il est toujours signalé correctement.la source
function logErrors(e){console.error(e)}
puis utilisez-le commedo1().then(do2).catch(logErrors)
. La réponse elle-même est géniale btw, +1window.onerror
gestionnaire d'événements. Ce n'est qu'en faisant lesetTimeout
tour que cela peut être fait. Sinonwindow.onerror
, vous n'entendrez jamais rien des erreurs survenues dans Promise.console.log
oupostErrorToServer
, vous pouvez simplement faire ce qui doit être fait. Il n'y a aucune raison pour laquelle le code qui se trouvewindow.onerror
ne peut pas être pris en compte dans une fonction distincte et être appelé à partir de 2 endroits. C'est probablement encore plus court que lasetTimeout
ligne.Choses importantes à comprendre ici
Les fonctions
then
etcatch
renvoient de nouveaux objets de promesse.Le fait de lancer ou de rejeter explicitement fera passer la promesse actuelle à l'état rejeté.
Depuis
then
etcatch
renvoyer de nouveaux objets de promesse, ils peuvent être enchaînés.Si vous lancez ou rejetez dans un gestionnaire de promesses (
then
oucatch
), il sera traité dans le prochain gestionnaire de rejet sur le chemin de chaînage.Comme mentionné par jfriend00, les gestionnaires
then
etcatch
ne sont pas exécutés de manière synchrone. Quand un handler lance, cela prendra fin immédiatement. Ainsi, la pile sera déroulée et l'exception serait perdue. C'est pourquoi lancer une exception rejette la promesse actuelle.Dans votre cas, vous rejetez à l'intérieur
do1
en lançant unError
objet. Désormais, la promesse actuelle sera rejetée et le contrôle sera transféré au gestionnaire suivant, ce qui estthen
dans notre cas.Puisque le
then
gestionnaire n'a pas de gestionnaire de rejet, ledo2
ne sera pas exécuté du tout. Vous pouvez le confirmer en utilisant à l'console.log
intérieur. Étant donné que la promesse actuelle n'a pas de gestionnaire de rejet, elle sera également rejetée avec la valeur de rejet de la promesse précédente et le contrôle sera transféré au gestionnaire suivant qui estcatch
.Comme
catch
c'est un gestionnaire de rejet, lorsque vous le faites à l'console.log(err.stack);
intérieur, vous pouvez voir la trace de la pile d'erreurs. Maintenant, vous lancez unError
objet à partir de celui-ci, donc la promesse renvoyée parcatch
sera également dans un état rejeté.Puisque vous n'avez attaché aucun gestionnaire de rejet au
catch
, vous ne pouvez pas observer le rejet.Vous pouvez diviser la chaîne et mieux comprendre cela, comme ça
La sortie que vous obtiendrez sera quelque chose comme
Dans le
catch
gestionnaire 1, vous obtenez la valeur de l'promise
objet comme rejeté.De la même manière, la promesse retournée par le
catch
gestionnaire 1 est également rejetée avec la même erreur avec laquelle le apromise
été rejeté et nous l'observons dans le secondcatch
gestionnaire.la source
.then()
gestionnaires sont asynchrones (la pile est déroulée avant d'être exécutés), donc les exceptions à l'intérieur doivent être transformées en rejets, sinon il n'y aurait pas de gestionnaires d'exceptions pour les attraper.J'ai essayé la
setTimeout()
méthode détaillée ci-dessus ...Malheureusement, j'ai trouvé cela complètement impossible à tester. Dans la mesure où il génère une erreur asynchrone, vous ne pouvez pas l'envelopper dans une
try/catch
instruction, carcatch
il aura cessé d'écouter au moment où l'erreur est générée.Je suis revenu à utiliser simplement un auditeur qui fonctionnait parfaitement et, parce que c'est ainsi que JavaScript est censé être utilisé, était hautement testable.
la source
Selon la spécification (voir 3.III.d) :
Cela signifie que si vous lancez une exception dans la
then
fonction, elle sera interceptée et votre promesse sera rejetée.catch
ça n'a pas de sens ici, c'est juste un raccourci vers.then(null, function() {})
Je suppose que vous voulez enregistrer les rejets non gérés dans votre code. La plupart des bibliothèques promettent un
unhandledRejection
pour cela. Voici l' essentiel pertinent avec une discussion à ce sujet.la source
unhandledRejection
hook est pour JavaScript côté serveur, du côté client, différents navigateurs ont des solutions différentes. NOUS ne l'avons pas encore normalisé mais il y arrive lentement mais sûrement.Je sais que c'est un peu tard, mais je suis tombé sur ce fil, et aucune des solutions n'était facile à mettre en œuvre pour moi, alors j'ai proposé la mienne:
J'ai ajouté une petite fonction d'aide qui renvoie une promesse, comme ceci:
Ensuite, si j'ai une place spécifique dans l'une de mes chaînes de promesses où je veux lancer une erreur (et rejeter la promesse), je reviens simplement de la fonction ci-dessus avec mon erreur construite, comme ceci:
De cette façon, je suis en contrôle de lancer des erreurs supplémentaires de l'intérieur de la chaîne de promesses. Si vous souhaitez également gérer les erreurs de promesse «normales», vous étendrez votre capture pour traiter séparément les erreurs «auto-lancées».
J'espère que cela aide, c'est ma première réponse stackoverflow!
la source
Promise.reject(error)
au lieu denew Promise(function (resolve, reject){ reject(error) })
(qui aurait besoin d'une déclaration de retour de toute façon)Oui promet d'avaler des erreurs, et vous ne pouvez les attraper qu'avec
.catch
, comme expliqué plus en détail dans d'autres réponses. Si vous êtes dans Node.js et que vous souhaitez reproduire lethrow
comportement normal , en imprimant la trace de la pile sur la console et en quittant le processus, vous pouvez fairela source
unhandledRejection
événement