web-dev-qa-db-fra.com

Comment attraper une exception non capturée dans Promise

Existe-t-il un moyen de capturer globalement toutes les exceptions, y compris les exceptions Promise. Exemple:

    window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
        alert("Error occured: " + errorMsg);//or any message
        return false;
    }

    var myClass = function(){

    }


    var pr = new Promise(function(resolve, react){
        var myInstance = new myClass();
        myInstance.undefinedFunction(); // this will throw Exception
        resolve(myInstance);
    });


    pr.then(function(result){
        console.log(result);
    });

    // i know right will be this:
    // pr.then(function(result){
    //     console.log(result);
    // }).catch(function(e){
    //     console.log(e);
    // });

Ce script va mourir silencieusement sans erreur. Rien dans Firebug.

Ma question est la suivante: si je fais une erreur en oubliant de l'attraper, y a-t-il un moyen de l'attraper à l'échelle mondiale?

65
John

Mise à jour, les promesses natives font maintenant ce qui suit dans la plupart des navigateurs:

window.addEventListener("unhandledrejection", function(promiseRejectionEvent) { 
    // handle error here, for example log   
});

Nous discutions de cela l'autre jour.

Voici comment vous feriez cela avec bluebird:

window.onpossiblyunhandledexception = function(){
    window.onerror.apply(this, arguments); // call
}

window.onerror = function(err){
    console.log(err); // logs all errors
}

Avec Bluebird, il est également possible d'utiliser Promise.onPossiblyUnhandledRejection. Les appels à done ne sont pas nécessaires, car la bibliothèque détectera elle-même le rejet non pris en charge, contrairement à Q (UPDATE 2016 - j'ai maintenant écrit le code pour Q et cela se fait).

En ce qui concerne les promesses natives - , elles seront éventuellement rapportées à window.onerror ou à un nouveau gestionnaire, mais le processus de spécification n’est pas encore terminé - vous pouvez suivez-le ici .

24
Benjamin Gruenbaum

La plupart des implémentations de promesse ne fournissent pas actuellement le type de fonctionnalité auquel vous faites référence, mais un certain nombre de bibliothèques de promesse tierces (y compris Q et bluebird ) fournit une méthode done() qui capture et rediffuse les erreurs non interceptées, les envoyant ainsi à la console.

( Edit: Voir la réponse de Benjamin Gruenbaum sur les fonctionnalités de Bluebird pour la gestion des exceptions non capturées)

Donc, si vous avez cela, vous devez simplement suivre la règle de base selon laquelle toute promesse que vous utilisez doit être soit retournée, soit résiliée avec .done():

pr.then(function(result){
    console.log(result);
})
.done();

Pour citer la référence Q API:

La règle d'or de done et de then est: soit return votre promesse à quelqu'un d'autre, ou si la chaîne se termine avec vous, appelez done pour le terminer. Terminer avec catch n'est pas suffisant car le gestionnaire catch peut lui-même renvoyer une erreur.

Je me rends compte que cela nécessite encore un peu de travail supplémentaire et vous pouvez toujours oublier de le faire, mais c'est une amélioration par rapport à l'obligation de .catch() et de gérer explicitement chaque erreur, en particulier pour la raison indiquée ci-dessus.

15
JLRishe

Dans Node.js, vous pouvez utiliser:

process.on('unhandledRejection', (reason, promise) => {
  console.error(`Uncaught error in`, promise);
});
4
JussiR

Si vous écrivez du code pouvant être exécuté à la fois dans un navigateur et dans un environnement Node.js, vous pouvez envelopper votre code dans une fonction à exécution automatique comme celle-ci:

var isNode = (typeof process !== 'undefined' && typeof process.on !== 'undefined');
(function(on, unhandledRejection) {
    // PUT ANY CODE HERE
    on(unhandledRejection, function(error, promise) {
        console.error(`Uncaught error in`, promise);
    });
    // PUT ANY CODE HERE
})(
    isNode ? process.on.bind(process) : window.addEventListener.bind(window),
    isNode ? "unhandledRejection" : "unhandledrejection"
);

Que se passerait-il si vous utilisiez ce code:

  • Si vous l'exécutiez dans un environnement Node.js, votre gestionnaire serait associé à l'objet de processus et exécuté lorsque vous avez une exception non interceptée dans une promesse.

  • Si vous l'exécutiez dans un environnement de navigateur, votre gestionnaire serait attaché à l'objet window et exécuté lorsque vous avez une exception non interceptée dans une promesse et que votre navigateur prend en charge l'événement unhandledrejection.

  • Si vous l'exécutiez dans un environnement de navigateur sans la prise en charge de unhandledrejection, vous ne pourrez pas intercepter votre exception non capturée et votre gestionnaire d'événement unhandledrejection ne sera jamais déclenché, mais vous ne le feriez pas. obtenir des erreurs s'il n'y a aucune exception non interceptée.

2
John Slegers

Si vous utilisez Promise en natif, c'est assez simple.
Vous devez seulement .catch ceci rejette quelque part où.

ajax(request).catch(function(rejected){
      console.log(rejected);
});

Si je ne l'attrape pas quelque part, la promesse non piégée continuera à apparaître. Mais si je l'attrape quelque part ...

1
redyyu