Por que não consigo simplesmente inserir um Error
retorno de chamada de captura e permitir que o processo lide com o erro como se estivesse em outro escopo?
Se não o fizer, console.log(err)
nada será impresso e não sei nada sobre o que aconteceu. O processo acaba ...
Exemplo:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
Se os retornos de chamada são executados no thread principal, por que eles Error
são engolidos por um buraco negro?
javascript
asynchronous
promise
throw
es6-promise
demian85
fonte
fonte
.catch(…)
retorna..catch((e) => { throw new Error() })
, escreva.catch((e) => { return Promise.reject(new Error()) })
ou simplesmente.catch((e) => Promise.reject(new Error()))
Respostas:
Como outros explicaram, o "buraco negro" é porque jogar dentro de um
.catch
continua a corrente com uma promessa rejeitada, e você não tem mais capturas, levando a uma corrente não terminada, que engole erros (ruim!)Adicione mais uma captura para ver o que está acontecendo:
Uma captura no meio de uma cadeia é útil quando você deseja que a cadeia continue apesar de uma etapa com falha, mas um re-lançamento é útil para continuar falhando depois de fazer coisas como registro de informações ou etapas de limpeza, talvez até alterando qual erro é jogado.
Truque
Para fazer com que o erro apareça como um erro no console da web, como você pretendia originalmente, use este truque:
Até os números das linhas sobrevivem, então o link no console da web me leva diretamente ao arquivo e à linha onde ocorreu o erro (original).
Por que funciona
Qualquer exceção em uma função chamada como manipulador de cumprimento ou rejeição de promessa é convertida automaticamente em uma rejeição da promessa que você deve retornar. O código da promessa que chama sua função cuida disso.
Uma função chamada por setTimeout, por outro lado, sempre é executada no estado estável do JavaScript, ou seja, é executada em um novo ciclo no loop de eventos do JavaScript. Exceções não são detectadas por nada e chegam ao console da web. Como
err
contém todas as informações sobre o erro, incluindo a pilha original, o arquivo e o número da linha, ele ainda é relatado corretamente.fonte
function logErrors(e){console.error(e)}
então use-o comodo1().then(do2).catch(logErrors)
. A resposta em si é ótima, +1window.onerror
manipulador de eventos. Somente fazendo osetTimeout
truque isso pode ser feito. Caso contráriowindow.onerror
, nunca ouvirá nada sobre os erros ocorridos no Promise.console.log
ou nãopostErrorToServer
, você pode simplesmente fazer o que precisa ser feito. Não há razão para que o código estejawindow.onerror
inserido não pode ser fatorado em uma função separada e ser chamado de 2 lugares. Provavelmente é ainda mais curto que asetTimeout
linha.Coisas importantes a entender aqui
As funções
then
ecatch
retornam novos objetos de promessa.Lançar ou rejeitar explicitamente, moverá a promessa atual para o estado rejeitado.
Como
then
ecatch
retornar novos objetos de promessa, eles podem ser encadeados.Se você lançar ou rejeitar dentro de um manipulador de promessa (
then
oucatch
), ele será tratado no próximo manipulador de rejeição no caminho de encadeamento.Conforme mencionado por jfriend00, os manipuladores
then
ecatch
não são executados de forma síncrona. Quando um manipulador lança, ele termina imediatamente. Portanto, a pilha será desenrolada e a exceção será perdida. É por isso que lançar uma exceção rejeita a promessa atual.No seu caso, você está rejeitando
do1
por dentro jogando umError
objeto. Agora, a promessa atual estará no estado rejeitado e o controle será transferido para o próximo manipulador, que é othen
nosso caso.Como o
then
manipulador não possui um manipulador de rejeição,do2
ele não será executado. Você pode confirmar isso usandoconsole.log
dentro dele. Como a promessa atual não possui um manipulador de rejeição, ela também será rejeitada com o valor de rejeição da promessa anterior e o controle será transferido para o próximo manipulador que écatch
.Como
catch
é um manipulador de rejeição, quando você fazconsole.log(err.stack);
dentro dele, é possível ver o rastreamento da pilha de erros. Agora, você está jogando umError
objeto para que a promessa retornadacatch
também esteja no estado rejeitado.Como você não anexou nenhum manipulador de rejeição ao
catch
, não é possível observar a rejeição.Você pode dividir a cadeia e entender isso melhor, assim
A saída que você obterá será algo como
Dentro do
catch
manipulador 1, você está recebendo o valor dopromise
objeto como rejeitado.Da mesma forma, a promessa retornada pelo
catch
manipulador 1 também é rejeitada com o mesmo erro com o qual opromise
foi rejeitado e estamos observando-o no segundocatch
manipulador.fonte
.then()
manipuladores são assíncronos (a pilha é desenrolada antes de serem executados); portanto, as exceções dentro deles devem ser transformadas em rejeições, caso contrário não haveria manipuladores de exceção para capturá-los.Eu tentei o
setTimeout()
método detalhado acima ...Irritantemente, achei que isso era completamente não testável. Como está lançando um erro assíncrono, você não pode envolvê-lo em uma
try/catch
instrução, porque ocatch
item parou de escutar quando o erro é lançado.Voltei a usar apenas um ouvinte que funcionasse perfeitamente e, porque é como o JavaScript deve ser usado, era altamente testável.
fonte
De acordo com as especificações (ver 3.III.d) :
Isso significa que, se você der uma exceção na
then
função, ela será capturada e sua promessa será rejeitada.catch
não faz sentido aqui, é apenas um atalho para.then(null, function() {})
Acho que você deseja registrar rejeições não tratadas no seu código. A maioria das bibliotecas de promessas dispara
unhandledRejection
por isso. Aqui está a essência da discussão sobre o assunto.fonte
unhandledRejection
gancho é para JavaScript no servidor, no lado do cliente diferentes navegadores têm soluções diferentes. Ainda não o padronizamos, mas está chegando lá lenta mas seguramente.Eu sei que isso é um pouco tarde, mas me deparei com esse segmento, e nenhuma das soluções era fácil de implementar para mim, então criei as minhas:
Eu adicionei uma pequena função auxiliar que retorna uma promessa, assim:
Então, se eu tiver um lugar específico em qualquer uma das minhas cadeias de promessas em que desejo gerar um erro (e rejeitar a promessa), simplesmente retornarei da função acima com meu erro construído, da seguinte forma:
Dessa forma, estou no controle de lançar erros extras de dentro da cadeia de promessas. Se você também deseja lidar com erros de promessa 'normais', expanda sua captura para tratar os erros 'lançados automaticamente' separadamente.
Espero que isso ajude, é a minha primeira resposta de stackoverflow!
fonte
Promise.reject(error)
em vez denew Promise(function (resolve, reject){ reject(error) })
(o que seria necessário um qualquer maneira instrução de retorno)Sim promete erros de andorinha, e você só pode pegá-los
.catch
, como explicado em detalhes em outras respostas. Se você estiver no Node.js e desejar reproduzir othrow
comportamento normal , imprimindo o rastreamento da pilha para o console e sair do processo, poderá fazerfonte
unhandledRejection
evento