Che cos'è un rifiuto di promessa non gestita?


203

Per l'apprendimento di Angular 2, sto provando il loro tutorial.

Ricevo un errore come questo:

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

Ho esaminato diverse domande e risposte in SO ma non sono riuscito a scoprire che cos'è un "rifiuto di promessa non gestita".

Qualcuno può semplicemente spiegarmi di cosa si tratta e anche cos'è Error: spawn cmd ENOENT, quando si presenta e cosa devo controllare per eliminare questo avviso?


2
Ho perso questa domanda! Mi dispiace molto per questo avviso che è confuso: lo abbiamo davvero migliorato nel nuovo Node.js e presto renderemo tutto molto meglio!
Benjamin Gruenbaum,


@BenjaminGruenbaum, è già stato corretto? Ho avuto lo stesso errore sul nodo v12.16.1
Baby desta il

1
@Babydesta bene, mostriamo un errore migliore ora con una traccia dello stack ma non continuiamo a bloccare il nodo su rifiuti non gestiti. Probabilmente abbiamo solo bisogno di aprire un PR per farlo.
Benjamin Gruenbaum,

Risposte:


200

L'origine di questo errore sta nel fatto che ogni singola promessa dovrebbe gestire il rifiuto della promessa, cioè avere un .catch (...) . puoi evitare lo stesso aggiungendo .catch (...) a una promessa nel codice come indicato di seguito.

ad esempio, la funzione PTest () risolverà o rifiuterà una promessa in base al valore di una variabile 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");
});

In alcuni casi, il messaggio di "rifiuto della promessa non gestita" arriva anche se abbiamo scritto .catch (..) per le promesse. È tutto su come scrivi il tuo codice. Il codice seguente genererà "rifiuto di promessa non gestita" anche se stiamo gestendo 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 differenza è che non gestisci .catch(...)come catena ma come separato. Per qualche motivo, il motore JavaScript lo considera promettente senza rifiuto della promessa non gestita.


4
Sembra funzionare, se aggiungi myFunc = myFunct.then...il secondo esempio.
Einstein,

@einstein sembrerà funzionare perché stai ricreando la stessa catena del primo esempio:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock,

4
@einstein Nel tuo esempio incondizionato, quando dici "Per qualche motivo il motore di script Java lo considera promessa senza rifiuto della promessa non gestita", non è questo perché e potrebbe essere generata un'eccezione nella .then(() => {...})quale non stai gestendo? Non penso che questo stia facendo la stessa cosa di quando li incateni. È?
Simon Legg

8
@DKG Per quanto riguarda il tuo secondo punto, catchè uno zucchero sintattico per then(undefined, onRejected). Dato che hai già chiamato quindi su myfunc e che ha provocato un errore, non chiamerà più (indefinito, rifiutato) sulla stessa promessa.
Kevin Lee,

1
Dove cambiare? Sto usando ionic 3 quando ho colpito il comando andorid build cordic ionico dandomi questo errore.
Sagar Kodte,

34

Questo è quando un Promiseè completato con .reject()o è stata generata un'eccezione in un asynccodice eseguito e nessuno .catch()ha gestito il rifiuto.

Una promessa respinta è come un'eccezione che si diffonde verso il punto di ingresso dell'applicazione e fa sì che il gestore degli errori di root produca quell'output.

Guarda anche


Dove cambiare? Sto usando ionic 3 quando ho colpito il comando andorid build cordic ionico dandomi questo errore.
Sagar Kodte,

Difficile dirlo con queste informazioni. Ti suggerirei di provare a creare una riproduzione minima e di creare una nuova domanda per la tua situazione specifica.
Günter Zöchbauer,

ho aperto la grazia per questo. Si prega di vedere le cose stackoverflow.com/q/48145380/5383669~~V~~singular~~3rd
Sagar Kodte

22

Le promesse possono essere "gestite" dopo essere state respinte. Cioè, si può chiamare il richiamo del rifiuto di una promessa prima di fornire un gestore di cattura. Questo comportamento è un po 'fastidioso per me perché si può scrivere ...

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

... e in questo caso, la Promessa viene respinta silenziosamente. Se si dimentica di aggiungere un gestore catch, il codice continuerà a essere eseguito silenziosamente senza errori. Ciò potrebbe portare a bug persistenti e difficili da trovare.

Nel caso di Node.js, si parla di gestire questi rifiuti Promise non gestiti e di segnalare i problemi. Questo mi porta a ES7 async / waitit. Considera questo esempio:

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

Nell'esempio sopra, supponiamo che i denti Promise siano stati respinti (errore: fuori dal dentifricio!) Prima che getRoomTemperature fosse realizzato. In questo caso, ci sarebbe un rifiuto Promesso non gestito fino ad attendere i denti.

Il mio punto è questo ... se consideriamo un problema il rifiuto delle promesse non gestite, le promesse che vengono successivamente gestite da un'attesa potrebbero essere segnalate inavvertitamente come bug. Inoltre, se consideriamo i rifiuti non gestiti non promettenti, i bug legittimi potrebbero non essere segnalati.

Pensi su questo?

Questo è legato alla discussione trovata nel progetto Node.js qui:

Comportamento rilevamento rifiuto non gestito predefinito

se scrivi il codice in questo modo:

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
}

Quando viene richiamato getReadyForBed, questo creerà in modo sincrono la promessa finale (non restituita) - che avrà lo stesso errore di "rifiuto non gestito" di qualsiasi altra promessa (ovviamente potrebbe non essere nulla, a seconda del motore). (Trovo molto strano che la tua funzione non restituisca nulla, il che significa che la tua funzione asincrona produce una promessa per indefinito.

Se faccio una Promessa in questo momento senza una cattura e ne aggiungo una in seguito, la maggior parte delle implementazioni di "errore di rifiuto non gestito" ritrarrà effettivamente l'avviso quando lo gestirò in seguito. In altre parole, async / await non altera la discussione sul "rifiuto non gestito" in alcun modo che io possa vedere.

per evitare questo inconveniente, scrivere il codice in questo modo:

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

Si noti che ciò dovrebbe impedire qualsiasi rifiuto non gestito della promessa.


13

"DeprecationWarning: i rifiuti non gestiti della promessa sono deprecati"

TLDR: una promessa ha resolvee reject, facendo una presa rejectsenza una presa per gestirla, è deprecata, quindi dovrai almeno avere un catchlivello superiore.


2

Nel mio caso Promise non ha rifiutato né risolto, perché la mia funzione Promise ha generato un'eccezione. Questo errore causa il messaggio UnhandledPromiseRejectionWarning.


1

Quando creo un'istanza di una promessa, ho intenzione di generare una funzione asincrona. Se la funzione va bene, allora chiamo RESOLVE, quindi il flusso continua nel gestore RESOLVE, in THEN. Se la funzione fallisce, quindi terminare la funzione chiamando REJECT, quindi il flusso continua nel CATCH.

In NodeJs è obsoleto il gestore di rifiuto. Il tuo errore è solo un avvertimento e l'ho letto all'interno di node.js github. Ho trovato questo.

DEP0018: Rifiuti promettenti non gestiti

Tipo: Runtime

I rifiuti promettenti non gestiti sono deprecati. In futuro, i rifiuti promettenti che non vengono gestiti interromperanno il processo Node.js con un codice di uscita diverso da zero.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.