O que é uma rejeição de promessa não tratada?

203

Para aprender Angular 2, estou tentando o tutorial.

Estou recebendo um erro como este:

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

Passei por perguntas e respostas diferentes no SO, mas não consegui descobrir o que é uma "Rejeição de promessa não tratada".

Alguém pode simplesmente me explicar o que é e também o que Error: spawn cmd ENOENTé, quando surge e o que tenho que verificar para me livrar desse aviso?

Mohammad Sadiqur Rahman
fonte
2
Eu perdi essa pergunta! Sinto muito por este aviso ser confuso - nós realmente o aprimoramos no Node.js mais recente e estamos melhorando tudo muito em breve!
Benjamin Gruenbaum
Possível duplicata de: stackoverflow.com/questions/38265963/…
Christophe Roussy 31/08
@BenjaminGruenbaum, já está consertado? Eu recebi o mesmo erro no nó v12.16.1
Baby desta
1
@Babydesta bem, agora mostramos um erro melhor com um rastreamento de pilha, mas ainda não travamos o nó em rejeições não tratadas. Provavelmente, precisamos apenas abrir um PR para fazer isso.
Benjamin Gruenbaum 16/04

Respostas:

200

A origem desse erro está no fato de que toda e qualquer promessa deve lidar com a rejeição da promessa, ou seja, ter uma captura. (...) . você pode evitar o mesmo adicionando .catch (...) a uma promessa no código, conforme indicado abaixo.

por exemplo, a função PTest () resolverá ou rejeitará uma promessa com base no valor de uma variável global em algum momento

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

Em alguns casos, a mensagem "rejeição de promessa não tratada" chega mesmo que tenhamos .catch (..) escrito para promessas. É tudo sobre como você escreve seu código. O código a seguir gerará "rejeição de promessa não tratada", mesmo que estejamos manipulando 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");
});

A diferença é que você não manipula .catch(...)como corrente, mas como separado. Por alguma razão, o mecanismo JavaScript o trata como promessa sem rejeição de promessa não tratada.

Daksh
fonte
4
Parece funcionar, se você adicionar myFunc = myFunct.then...no segundo exemplo.
einstein
@einstein parecerá funcionar porque você está recriando a mesma cadeia que no primeiro exemplo:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock
4
@einstein No seu exemplo desencadeado, quando você diz "Por algum motivo, o mecanismo Java Script o trata como promessa sem rejeição de promessa não tratada", não é porque uma exceção pode ser lançada na .then(() => {...})qual você não está lidando? Eu não acho que isso esteja fazendo a mesma coisa que quando você os encadeia. É isso?
Simon Legg
8
@DKG Em relação ao seu segundo ponto, catché um açúcar de sintaxe para then(undefined, onRejected). Desde que você já ligou no myfunc e que acionou um erro, ele não ligará novamente (indefinido, onRejected) com a mesma promessa novamente.
Kevin Lee
1
Onde mudar? Estou usando o ionic 3 quando bati no comando andorid ionova cordova build, me dando esse erro.
Sagar Kodte
34

É quando um Promiseé concluído .reject()ou uma exceção foi lançada em um asynccódigo executado e nenhum.catch() não manipula a rejeição.

Uma promessa rejeitada é como uma exceção que borbulha em direção ao ponto de entrada do aplicativo e faz com que o manipulador de erros raiz produza essa saída.

Veja também

Günter Zöchbauer
fonte
Onde mudar? Estou usando o ionic 3 quando bati no comando andorid ionova cordova build, me dando esse erro.
Sagar Kodte
Difícil dizer com esta informação. Eu sugiro que você tente criar uma reprodução mínima e criar uma nova pergunta para sua situação específica.
Günter Zöchbauer
Eu abri recompensas por isso. Por favor, veja-o stackoverflow.com/q/48145380/5383669
Sagar Kodte
22

As promessas podem ser "tratadas" após serem rejeitadas. Ou seja, é possível chamar o retorno de chamada rejeitada de uma promessa antes de fornecer um manipulador de captura. Esse comportamento é um pouco incômodo para mim, porque se pode escrever ...

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

... e, neste caso, a promessa é rejeitada silenciosamente. Se alguém esquecer de adicionar um manipulador de captura, o código continuará sendo executado silenciosamente, sem erros. Isso pode levar a erros persistentes e difíceis de encontrar.

No caso do Node.js, fala-se em lidar com essas rejeições não tratadas do Promise e em relatar os problemas. Isso me leva ao ES7 assíncrono / aguardado. Considere este exemplo:

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

No exemplo acima, suponha que teethPromise foi rejeitado (Erro: sem pasta de dente!) Antes que getRoomTemperature fosse atendido. Nesse caso, haveria uma rejeição não tratada da promessa até aguardar os dentes.

O que quero dizer é que ... se considerarmos que as rejeições de Promessa não tratadas são um problema, promessas que são tratadas posteriormente por uma espera podem ser inadvertidamente relatadas como bugs. Por outro lado, se considerarmos que as rejeições por promessa não tratadas não são problemáticas, os erros legítimos podem não ser relatados.

Pensamentos sobre isso?

Isso está relacionado à discussão encontrada no projeto Node.js. aqui:

Comportamento de detecção de rejeição não tratada padrão

se você escrever o código desta maneira:

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 getReadyForBed é chamado, ele cria de forma síncrona a promessa final (não retornada) - que terá o mesmo erro de "rejeição sem tratamento" que qualquer outra promessa (pode não ser nada, é claro, dependendo do mecanismo). (Acho muito estranho que sua função não retorne nada, o que significa que sua função assíncrona produz uma promessa indefinida.

Se eu fizer uma Promessa agora sem uma captura e adicionar uma mais tarde, a maioria das implementações de "erro de rejeição sem tratamento" retrairá o aviso quando eu o tratar posteriormente. Em outras palavras, async / waitit não altera a discussão sobre "rejeição sem tratamento" de qualquer maneira que eu possa ver.

Para evitar essa armadilha, escreva o código desta maneira:

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

Observe que isso deve impedir qualquer rejeição de promessa não tratada.

programador anis
fonte
13

"DeprecationWarning: Unhandled rejeições promessa estão obsoletos"

TLDR: Uma promessa tem resolvee reject, fazendo um rejectsem uma captura de lidar com isso é obsoleto, por isso você terá que ter pelo menos um catchnível superior.

Christophe Roussy
fonte
2

No meu caso, foi Promise sem rejeição nem resolução, porque minha função Promise lançou uma exceção. Esse erro causa a mensagem UnhandledPromiseRejectionWarning.

Diniz
fonte
1

Quando instancia uma promessa, vou gerar uma função assíncrona. Se a função for bem, eu chamo RESOLVE, e o fluxo continua no manipulador RESOLVE, no THEN. Se a função falhar, encerre a função chamando REJECT, em seguida, o fluxo continuará no CATCH.

Nos NodeJs, o manipulador de rejeição foi reprovado. Seu erro é apenas um aviso e eu o li no node.js github. Eu achei isto.

DEP0018: Rejeições de promessa não tratadas

Tipo: Tempo de execução

As rejeições de promessa não tratadas foram preteridas. No futuro, as rejeições de promessa que não forem tratadas encerrarão o processo Node.js. com um código de saída diferente de zero.

Κωλζαρ
fonte