Qu'est-ce qu'un rejet de promesse non géré?

203

Pour apprendre Angular 2, j'essaie leur tutoriel.

Je reçois une erreur comme celle-ci:

(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r                                                                                                     ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the Node.
js process with a non-zero exit code.

J'ai parcouru différentes questions et réponses dans SO, mais je n'ai pas pu découvrir ce qu'est un «rejet de promesse non géré».

Quelqu'un peut-il simplement m'expliquer de quoi il s'agit et aussi de quoi il Error: spawn cmd ENOENTs'agit, quand il survient et ce que je dois vérifier pour me débarrasser de cet avertissement?

Mohammad Sadiqur Rahman
la source
2
J'ai raté cette question! Je suis vraiment désolé pour cet avertissement, c'est déroutant - nous l'avons vraiment amélioré dans les nouveaux Node.js et nous améliorons le tout bientôt!
Benjamin Gruenbaum
Copie possible de: stackoverflow.com/questions/38265963/…
Christophe Roussy
@BenjaminGruenbaum, est-il encore corrigé? J'ai eu la même erreur sur le noeud v12.16.1
Baby desta
1
@Babydesta bien, nous montrons maintenant une meilleure erreur avec une trace de pile mais nous ne plantons toujours pas le nœud sur les rejets non gérés. Nous avons probablement juste besoin d'ouvrir un PR pour le faire.
Benjamin Gruenbaum

Réponses:

200

L'origine de cette erreur réside dans le fait que chaque promesse est censée gérer le rejet de la promesse, c'est-à-dire avoir un .catch (...) . vous pouvez éviter la même chose en ajoutant .catch (...) à une promesse dans le code comme indiqué ci-dessous.

par exemple, la fonction PTest () résoudra ou rejettera une promesse basée sur la valeur d'une variable globale somevar

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
}).catch(function () {
     console.log("Promise Rejected");
});

Dans certains cas, le message "rejet de promesse non géré" apparaît même si nous avons écrit .catch (..) pour les promesses. Tout dépend de la façon dont vous écrivez votre code. Le code suivant générera un "rejet de promesse non géré" même si nous le gérons catch.

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
});
// See the Difference here
myfunc.catch(function () {
     console.log("Promise Rejected");
});

La différence est que vous ne gérez pas .catch(...)comme une chaîne mais comme une chaîne séparée. Pour une raison quelconque, le moteur JavaScript le traite comme une promesse sans rejet de promesse non géré.

Daksh
la source
4
Cela semble fonctionner, si vous ajoutez myFunc = myFunct.then...dans le deuxième exemple.
einstein
@einstein, cela semble fonctionner parce que vous recréez la même chaîne que dans le premier exemple:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock
4
@einstein Dans votre exemple déchaîné, lorsque vous dites "Pour une raison quelconque, le moteur Java Script le traite comme une promesse sans rejet de promesse non géré", n'est-ce pas parce qu'une exception pourrait être lancée dans ce .then(() => {...})que vous ne gérez pas ? Je ne pense pas que cela fasse la même chose que lorsque vous les enchaînez. C'est ça?
Simon Legg
8
@DKG Concernant votre deuxième point, catchest un sucre de syntaxe pour then(undefined, onRejected). Puisque vous avez déjà appelé alors sur myfunc et que cela a déclenché une erreur, il ne va pas appeler à nouveau (non défini, onRejected) sur la même promesse.
Kevin Lee
1
Où changer? J'utilise ionic 3 lorsque je frappe la commande ionic cordova build andorid me donnant cette erreur.
Sagar Kodte
34

C'est quand un Promiseest terminé avec .reject()ou une exception a été levée dans un asynccode exécuté et aucun .catch()n'a géré le rejet.

Une promesse rejetée est comme une exception qui se propage vers le point d'entrée de l'application et fait que le gestionnaire d'erreurs racine produit cette sortie.

Voir également

Günter Zöchbauer
la source
Où changer? J'utilise ionic 3 lorsque je frappe la commande ionic cordova build andorid me donnant cette erreur.
Sagar Kodte
Difficile à dire avec ces informations. Je vous suggère d'essayer de créer une reproduction minimale et de créer une nouvelle question pour votre situation spécifique.
Günter Zöchbauer
j'ai ouvert la prime pour cela. Veuillez le regarder stackoverflow.com/q/48145380/5383669
Sagar Kodte
22

Les promesses peuvent être "traitées" après avoir été rejetées. Autrement dit, on peut appeler le rappel de rejet d'une promesse avant de fournir un gestionnaire de capture. Ce comportement me dérange un peu car on peut écrire ...

var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });

... et dans ce cas, la Promesse est rejetée en silence. Si l'on oublie d'ajouter un gestionnaire de capture, le code continuera de s'exécuter silencieusement sans erreur. Cela pourrait conduire à des bogues persistants et difficiles à trouver.

Dans le cas de Node.js, il est question de gérer ces rejets de promesse non gérés et de signaler les problèmes. Cela m'amène à ES7 async / wait. Considérez cet exemple:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  let temp = await tempPromise;
  // Assume `changeClothes` also returns a Promise
  if(temp > 20) {
    await changeClothes("warm");
  } else {
    await changeClothes("cold");
  }

  await teethPromise;
}

Dans l'exemple ci-dessus, supposons que toothPromise a été rejetée (erreur: sans dentifrice!) Avant que getRoomTemperature ne soit remplie. Dans ce cas, il y aurait un rejet de promesse non géré jusqu'à l'attente de toothPromise.

Mon point est le suivant ... si nous considérons les rejets de promesses non gérés comme un problème, les promesses qui sont ensuite traitées par un attente peuvent être signalées par inadvertance comme des bogues. Là encore, si nous considérons que les rejets de promesses non gérés ne sont pas problématiques, les bugs légitimes pourraient ne pas être signalés.

Réflexions là-dessus?

Ceci est lié à la discussion trouvée dans le projet Node.js ici:

Comportement de détection de rejet non géré par défaut

si vous écrivez le code de cette façon:

function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  return Promise.resolve(tempPromise)
    .then(temp => {
      // Assume `changeClothes` also returns a Promise
      if (temp > 20) {
        return Promise.resolve(changeClothes("warm"));
      } else {
        return Promise.resolve(changeClothes("cold"));
      }
    })
    .then(teethPromise)
    .then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
}

Lorsque getReadyForBed est invoqué, il créera de manière synchrone la promesse finale (non retournée) - qui aura la même erreur de "rejet non géré" que toute autre promesse (cela pourrait être rien, bien sûr, selon le moteur). (Je trouve très étrange que votre fonction ne retourne rien, ce qui signifie que votre fonction asynchrone produit une promesse non définie.

Si je fais une promesse en ce moment sans problème et que j'en ajoute une plus tard, la plupart des implémentations d '"erreur de rejet non gérée" retireront réellement l'avertissement lorsque je le gérerai plus tard. En d'autres termes, async / wait ne modifie en rien la discussion sur le "rejet non géré".

pour éviter cet écueil, veuillez écrire le code de cette façon:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  var clothesPromise = tempPromise.then(function(temp) {
    // Assume `changeClothes` also returns a Promise
    if(temp > 20) {
      return changeClothes("warm");
    } else {
      return changeClothes("cold");
    }
  });
  /* Note that clothesPromise resolves to the result of `changeClothes`
     due to Promise "chaining" magic. */

  // Combine promises and await them both
  await Promise.all(teethPromise, clothesPromise);
}

Notez que cela devrait empêcher tout rejet de promesse non géré.

programmeur anis
la source
13

"DeprecationWarning: les refus de promesses non gérés sont dépréciés"

TLDR: Une promesse a resolveet reject, faire un rejectsans catch pour le gérer est déprécié, vous devrez donc au moins en avoir un catchau plus haut niveau.

Christophe Roussy
la source
2

Dans mon cas, Promise ne rejetait ni ne résolvait, car ma fonction Promise lançait une exception. Cette erreur provoque le message UnhandledPromiseRejectionWarning.

Diniz
la source
1

Lorsque j'instancie une promesse, je vais générer une fonction asynchrone. Si la fonction se passe bien, j'appelle RESOLVE puis le flux continue dans le gestionnaire RESOLVE, dans THEN. Si la fonction échoue, mettez fin à la fonction en appelant REJECT puis le flux continue dans le CATCH.

Dans NodeJs, le gestionnaire de rejet est obsolète. Votre erreur n'est qu'un avertissement et je l'ai lu dans github node.js. J'ai trouvé ça.

DEP0018: Rejets de promesses non gérés

Type: Runtime

Les refus de promesse non gérés sont dépréciés. À l'avenir, les refus de promesse qui ne sont pas traités mettront fin au processus Node.js avec un code de sortie différent de zéro.

Κωλζαρ
la source