Co to jest nieobsługiwane odrzucenie obietnicy?


203

Do nauki gry Angular 2 próbuję ich samouczka.

Otrzymuję taki błąd:

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

Przeanalizowałem różne pytania i odpowiedzi w SO, ale nie mogłem dowiedzieć się, co to jest „nieobsługiwane odrzucenie obietnicy”.

Czy ktoś może mi po prostu wyjaśnić, co to jest, a także co Error: spawn cmd ENOENT, kiedy się pojawi i co muszę sprawdzić, aby pozbyć się tego ostrzeżenia?


2
Brakowało mi tego pytania! Bardzo przepraszam za to ostrzeżenie, które jest mylące - naprawdę poprawiliśmy je w nowszych wersjach Node.js i wkrótce poprawimy to wszystko!
Benjamin Gruenbaum,


@BenjaminGruenbaum, czy to już jest naprawione? Otrzymałem ten sam błąd w węźle 12.12.1
Baby

1
@Babydesta dobrze, teraz pokazujemy lepszy błąd ze śledzeniem stosu, ale nadal nie zawieszamy węzła przy nieobsługiwanych odrzuceniach. Prawdopodobnie musimy po prostu otworzyć PR, aby to zrobić.
Benjamin Gruenbaum

Odpowiedzi:


200

Przyczyną tego błędu jest to, że oczekuje się, że każda obietnica poradzi sobie z odrzuceniem obietnicy, tj. Będzie miała .catch (...) . możesz tego uniknąć, dodając .catch (...) do obietnicy w kodzie, jak podano poniżej.

Na przykład, funkcja Ptest () będzie albo postanowienie lub odrzucić obietnica na podstawie wartości globalnej zmiennej 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");
});

W niektórych przypadkach pojawia się komunikat „nieobsługiwane odrzucenie obietnicy”, nawet jeśli mamy .catch (..) napisane dla obietnic. Wszystko zależy od tego, jak piszesz swój kod. Poniższy kod wygeneruje „nieobsługiwane odrzucenie obietnicy”, mimo że jesteśmy w stanie to zrobić 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");
});

Różnica polega na tym, że nie traktujesz .catch(...)jak łańcuch, ale jako osobne. Z jakiegoś powodu silnik JavaScript traktuje to jako obietnicę bez nieobsługiwanego odrzucenia obietnicy.


4
Wydaje się, że działa, jeśli dodasz myFunc = myFunct.then...w drugim przykładzie.
einstein

@einstein będzie działał, ponieważ odtwarzasz ten sam łańcuch, co w pierwszym przykładzie:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein W swoim niezbadanym przykładzie, gdy mówisz „Z jakiegoś powodu silnik Java Script traktuje to jako obietnicę bez nieobsługiwanego odrzucenia obietnicy”, czyż nie jest to spowodowane tym, że wyjątek mógłby zostać wrzucony w to, .then(() => {...})czego nie obsługujesz? Nie sądzę, że robi to to samo, co kiedy je łączysz. Czy to jest
Simon Legg,

8
@DKG Jeśli chodzi o twój drugi punkt, catchto cukier składniowy then(undefined, onRejected). Ponieważ już zadzwoniłeś wtedy na myfunc, co spowodowało błąd, nie będzie wtedy wywoływał (niezdefiniowany, onRejected) na tej samej obietnicy.
Kevin Lee

1
Gdzie się zmienić? Korzystam z ionic 3, gdy uderzę w komendę build andorid ionic cordova, co daje mi ten błąd.
Sagar Kodte

34

Dzieje się tak, gdy a Promisejest zakończone .reject()lub został wygenerowany wyjątek w asyncwykonanym kodzie i żadne .catch()nie obsłużyło odrzucenia.

Odrzucona obietnica jest jak wyjątek, który przesuwa się w kierunku punktu wejścia aplikacji i powoduje, że program obsługi błędów root generuje ten wynik.

Zobacz też


Gdzie się zmienić? Korzystam z ionic 3, gdy uderzę w komendę build andorid ionic cordova, co daje mi ten błąd.
Sagar Kodte

Trudno powiedzieć na podstawie tych informacji. Sugeruję, abyś spróbował stworzyć minimalną reprodukcję i stworzyć nowe pytanie dotyczące konkretnej sytuacji.
Günter Zöchbauer,

Otworzyłem nagrodę za to. Proszę spojrzeć na to stackoverflow.com/q/48145380/5383669
Sagar Kodte

22

Obietnice można „obsłużyć” po ich odrzuceniu. Oznacza to, że można wywołać wywołanie zwrotne odrzucenia obietnicy przed udostępnieniem modułu obsługi przechwytywania. To zachowanie jest dla mnie trochę uciążliwe, ponieważ można pisać ...

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

... iw tym przypadku obietnica zostaje odrzucona w milczeniu. Jeśli zapomnisz dodać moduł obsługi przechwytywania, kod będzie działał w trybie cichym bez błędów. Może to prowadzić do utrzymujących się i trudnych do znalezienia błędów.

W przypadku Node.js mówi się o obsłudze tych nieobsługiwanych odrzuceń Promise i zgłaszaniu problemów. To prowadzi mnie do ES7 async / czekaj. Rozważ ten przykład:

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

W powyższym przykładzie załóżmy, że toothPromise został odrzucony (Błąd: z pasty do zębów!), Zanim getRoomTemperature został spełniony. W takim przypadku nastąpi nieobsługiwane odrzucenie obietnicy do czasu oczekiwania na zęby Promise.

Chodzi mi o to ... jeśli weźmiemy pod uwagę nieobsługiwane odrzucenie obietnicy jako problem, obietnice, które są później obsługiwane przez oczekiwanie, mogą zostać przypadkowo zgłoszone jako błędy. Z drugiej strony, jeśli uznamy, że odrzucenie odrzuconych obietnic nie jest problematyczne, uzasadnione błędy mogą nie zostać zgłoszone.

Myśli na ten temat?

Jest to związane z dyskusją w projekcie Node.js tutaj:

Domyślne zachowanie wykrywania nieobsługiwanego odrzucenia

jeśli napiszesz kod w ten sposób:

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
}

Wywołanie getReadyForBed spowoduje synchroniczne utworzenie ostatecznej (nie zwróconej) obietnicy - która będzie miała taki sam błąd „nieobsługiwanego odrzucenia” jak każda inna obietnica (oczywiście może to być nic, w zależności od silnika). (Uważam za bardzo dziwne, że twoja funkcja nic nie zwraca, co oznacza, że ​​twoja funkcja asynchroniczna daje obietnicę dla niezdefiniowanej.

Jeśli złożę teraz obietnicę bez połowu i dodam ją później, większość implementacji „nieobsługiwanego błędu odrzucenia” faktycznie cofnie to ostrzeżenie, gdy później to zrobię. Innymi słowy, asynchronizacja / oczekiwanie nie zmienia dyskusji o „nieobsługiwanym odrzuceniu” w żaden sposób, jaki widzę.

aby uniknąć tej pułapki, napisz kod w ten sposób:

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

Pamiętaj, że powinno to zapobiegać wszelkim nieobsługiwanym odrzuceniu obietnicy.


13

„Przestarzałe ostrzeżenie: nieobsługiwane odrzucenia obietnic są przestarzałe”

TLDR: Obietnica ma, resolvea rejectzrobienie rejectbez haczyka do jej obsługi jest przestarzała, więc będziesz musiał mieć przynajmniej catchnajwyższy poziom.


2

W moim przypadku była to Obietnica bez odrzucenia ani rozstrzygnięcia, ponieważ moja funkcja Obietnicy rzuciła wyjątek. Ten błąd powoduje komunikat UnhandledPromiseRejectionWarning.


1

Kiedy utworzę obietnicę, wygeneruję funkcję asynchroniczną. Jeśli funkcja działa dobrze, to wywołuję RESOLVE, a następnie przepływ jest kontynuowany w module obsługi RESOLVE, a następnie. Jeśli funkcja zawiedzie, należy ją zakończyć, wywołując REJECT, a następnie przepływ jest kontynuowany w POŁOWIE.

W NodeJ są przestarzałe moduł obsługi odrzucania. Twój błąd jest tylko ostrzeżeniem i przeczytałem go w github node.js. Znalazłem to.

DEP0018: Nieobsługiwane odrzucenia obietnicy

Wpisz: Runtime

Nieobsługiwane odrzucenia obietnic są przestarzałe. W przyszłości odrzucone obietnice, które nie zostaną obsłużone, zakończą proces Node.js kodem wyjścia niezerowym.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.