Was ist eine unbehandelte Ablehnung eines Versprechens?

203

Um Angular 2 zu lernen, versuche ich ihr Tutorial.

Ich erhalte folgende Fehlermeldung:

(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.

Ich habe in SO verschiedene Fragen und Antworten durchgearbeitet, konnte aber nicht herausfinden, was eine "unbehandelte Ablehnung von Versprechungen" ist.

Kann mir jemand einfach erklären, was es ist und was es Error: spawn cmd ENOENTist, wann es auftritt und was ich überprüfen muss, um diese Warnung loszuwerden?

Mohammad Sadiqur Rahman
quelle
2
Ich habe diese Frage verpasst! Es tut mir so leid für diese Warnung, dass sie verwirrend ist - wir haben sie in neueren Node.js wirklich verbessert und wir machen das Ganze bald viel besser!
Benjamin Gruenbaum
Mögliches Duplikat von: stackoverflow.com/questions/38265963/…
Christophe Roussy
@BenjaminGruenbaum, ist es schon behoben? Ich habe den gleichen Fehler auf Knoten v12.16.1
Baby desta
1
@Babydesta Nun, wir zeigen jetzt einen besseren Fehler mit einem Stack-Trace, aber wir stürzen den Knoten bei nicht behandelten Ablehnungen immer noch nicht ab. Wir müssen wahrscheinlich nur eine PR eröffnen, um das zu tun.
Benjamin Gruenbaum

Antworten:

199

Der Ursprung dieses Fehlers liegt in der Tatsache, dass von jedem Versprechen erwartet wird, dass es die Ablehnung von Versprechen behandelt, dh einen .catch (...) hat . Sie können dasselbe vermeiden, indem Sie .catch (...) zu einem Versprechen im Code hinzufügen, wie unten angegeben.

Beispielsweise löst die Funktion PTest () ein Versprechen basierend auf dem Wert einer globalen Variablen somevar auf oder lehnt es ab

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

In einigen Fällen wird die Meldung "Nicht behandelte Versprechen ablehnen" auch dann angezeigt, wenn .catch (..) für Versprechen geschrieben wurde. Es geht darum, wie Sie Ihren Code schreiben. Der folgende Code generiert eine "unbehandelte Ablehnung von Versprechungen" , obwohl wir damit umgehencatch .

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

Der Unterschied ist, dass Sie nicht .catch(...)als Kette, sondern als separate behandeln. Aus irgendeinem Grund behandelt die JavaScript-Engine es als Versprechen ohne unbehandelte Ablehnung von Versprechen.

Daksh
quelle
4
Es scheint zu funktionieren, wenn Sie myFunc = myFunct.then...im zweiten Beispiel hinzufügen .
Einstein
@einstein es scheint zu funktionieren, weil Sie die gleiche Kette wie im ersten Beispiel neu var x = foo(); x = x.then(...); x = x.catch(...)
erstellen
4
@einstein Wenn Sie in Ihrem nicht verketteten Beispiel sagen: "Aus irgendeinem Grund behandelt die Java Script Engine es als Versprechen ohne nicht behandelte Ablehnung von Versprechen", liegt das nicht daran, dass eine Ausnahme in das ausgelöst werden könnte, .then(() => {...})das Sie nicht behandeln? Ich glaube nicht, dass dies dasselbe tut, als wenn Sie sie verketten. Ist es?
Simon Legg
8
@DKG In Bezug auf Ihren zweiten Punkt catchist eine Syntax Zucker für then(undefined, onRejected). Da Sie dann schon auf myfunc angerufen haben und dies einen Fehler ausgelöst hat, wird es dann nicht wieder (undefiniert, onRejected) auf dasselbe Versprechen zurückrufen.
Kevin Lee
1
Wo ändern? Ich verwende ionic 3, wenn ich den Befehl ionic cordova build andorid drücke und diesen Fehler erhalte.
Sagar Kodte
34

Dies ist der Fall, wenn a abgeschlossen Promiseist .reject()oder eine Ausnahme in einem asyncausgeführten Code ausgelöst wurde und no .catch()die Ablehnung behandelt hat.

Ein abgelehntes Versprechen ist wie eine Ausnahme, die in Richtung des Anwendungseintrittspunkts sprudelt und den Root-Fehlerbehandler veranlasst, diese Ausgabe zu erzeugen.

Siehe auch

Günter Zöchbauer
quelle
Wo ändern? Ich verwende ionic 3, wenn ich den Befehl ionic cordova build andorid drücke und diesen Fehler erhalte.
Sagar Kodte
Mit diesen Informationen schwer zu sagen. Ich würde vorschlagen, dass Sie versuchen, eine minimale Reproduktion zu erstellen und eine neue Frage für Ihre spezifische Situation zu erstellen.
Günter Zöchbauer
Ich habe Kopfgeld dafür eröffnet. Bitte schauen Sie es sich an stackoverflow.com/q/48145380/5383669
Sagar Kodte
22

Versprechen können "bearbeitet" werden, nachdem sie abgelehnt wurden. Das heißt, man kann den Ablehnungsrückruf eines Versprechens aufrufen, bevor man einen Catch-Handler bereitstellt. Dieses Verhalten ist für mich etwas störend, weil man schreiben kann ...

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

... und in diesem Fall wird das Versprechen stillschweigend abgelehnt. Wenn man vergisst, einen Catch-Handler hinzuzufügen, wird der Code weiterhin fehlerfrei ausgeführt. Dies könnte zu anhaltenden und schwer zu findenden Fehlern führen.

Im Fall von Node.js ist die Rede davon, diese nicht behandelten Ablehnungen von Versprechungen zu behandeln und die Probleme zu melden. Dies bringt mich zu ES7 async / await. Betrachten Sie dieses Beispiel:

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

Angenommen, im obigen Beispiel wurde ZähnePromise abgelehnt (Fehler: keine Zahnpasta mehr!), Bevor getRoomTemperature erfüllt wurde. In diesem Fall würde es eine unbehandelte Ablehnung des Versprechens geben, bis die Zähne warten.

Mein Punkt ist folgender: Wenn wir nicht behandelte Ablehnungen von Versprechungen als Problem betrachten, werden Versprechungen, die später von einem Warten behandelt werden, möglicherweise versehentlich als Fehler gemeldet. Wenn wir jedoch unbehandelte Ablehnungen von Versprechungen als unproblematisch betrachten, werden legitime Fehler möglicherweise nicht gemeldet.

Gedanken dazu?

Dies hängt mit der Diskussion zusammen, die im Node.js-Projekt hier zu finden ist:

Standardverhalten bei der Erkennung nicht behandelter Ablehnungen

Wenn Sie den Code folgendermaßen schreiben:

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
}

Wenn getReadyForBed aufgerufen wird, wird synchron das endgültige (nicht zurückgegebene) Versprechen erstellt, das den gleichen Fehler "Nicht behandelte Ablehnung" aufweist wie jedes andere Versprechen (kann natürlich nichts sein, abhängig von der Engine). (Ich finde es sehr seltsam, dass Ihre Funktion nichts zurückgibt, was bedeutet, dass Ihre asynchrone Funktion ein Versprechen für undefiniert erzeugt.

Wenn ich jetzt ein Versprechen ohne einen Haken mache und später einen hinzufüge, wird die Warnung von den meisten "nicht behandelten Ablehnungsfehler" -Implementierungen tatsächlich zurückgezogen, wenn ich sie später bearbeite. Mit anderen Worten, async / await ändert nichts an der Diskussion über "unbehandelte Ablehnung" in irgendeiner Weise, die ich sehen kann.

Um diese Gefahr zu vermeiden, schreiben Sie den Code bitte folgendermaßen:

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

Beachten Sie, dass dies eine unbehandelte Ablehnung von Versprechungen verhindern sollte.

Anis Programmierer
quelle
13

"DeprecationWarning: Nicht behandelte Ablehnungen von Versprechungen sind veraltet."

TLDR: Ein Versprechen hat resolveund rejecteine tun , rejectohne einen Haken zu handhaben es veraltet ist, so dass Sie haben zumindest ein catchauf höchstem Niveau.

Christophe Roussy
quelle
2

In meinem Fall war Promise ohne Ablehnung oder Auflösung, da meine Promise-Funktion eine Ausnahme auslöste. Dieser Fehler verursacht die Meldung UnhandledPromiseRejectionWarning.

Diniz
quelle
1

Wenn ich ein Versprechen instanziiere, werde ich eine asynchrone Funktion generieren. Wenn die Funktion gut funktioniert, rufe ich RESOLVE auf, und der Fluss wird im RESOLVE-Handler im THEN fortgesetzt. Wenn die Funktion fehlschlägt, beenden Sie die Funktion durch Aufrufen von REJECT. Anschließend wird der Ablauf im CATCH fortgesetzt.

In NodeJs ist der Ablehnungshandler veraltet. Ihr Fehler ist nur eine Warnung und ich habe ihn in node.js github gelesen. Ich habe das gefunden.

DEP0018: Nicht behandelte Ablehnungen von Versprechungen

Typ: Laufzeit

Nicht behandelte Ablehnungen von Versprechungen sind veraltet. In Zukunft beenden Versprechen, die nicht behandelt werden, den Node.js-Prozess mit einem Exit-Code ungleich Null.

Κωλζαρ
quelle