Tratamento de Erros em Promises JavaScript
Aprenda o tratamento de erros em promises JavaScript: .catch(), propagação de rejeições, relançamento, recuperação, .finally(), unhandledrejection e try/catch com async/await.
As promises JavaScript são uma parte fundamental do gerenciamento de operações assíncronas, permitindo que os desenvolvedores lidem com eventos assíncronos com mais flexibilidade e facilidade (veja JavaScript: Promises). O tratamento de erros em promises é essencial para escrever código JavaScript robusto, capaz de lidar com problemas inesperados sem travar a aplicação.
Este capítulo aborda como as rejeições são capturadas, como os erros fluem em uma cadeia, como relançar e recuperar, o gancho de limpeza .finally(), a rede de segurança global unhandledrejection, e como os mesmos padrões se mapeiam para async/await. Se você é novo no encadeamento de chamadas .then(), leia Encadeamento de Promises primeiro.
Uma promise pode terminar em um de dois estados: fulfilled (produziu um valor) ou rejected (algo deu errado). Uma rejeição ocorre quando você chama reject(...), quando você throw dentro de um executor ou de um callback .then(), ou quando uma API assíncrona nativa falha. O tratamento de erros consiste em direcionar essas rejeições para um handler em vez de deixá-las travar o programa.
O tratamento de erros em promises é realizado usando o método .catch() ou passando um segundo argumento para o método .then(). Ambos os métodos oferecem formas de gerenciar e se recuperar de erros que ocorrem durante a execução de operações assíncronas.
Usando o Método .catch()
O método .catch() é usado para capturar quaisquer erros que ocorram durante a execução da cadeia de promises.
Usando o Segundo Argumento de .then()
Como alternativa, um segundo argumento pode ser passado para .then() para tratar erros que ocorrem após a execução do callback do primeiro argumento.
Técnicas Avançadas de Tratamento de Erros
Fluxo de Erros em Cadeias
Os erros devem ser propagados corretamente pela cadeia de promises para garantir que sejam tratados no nível adequado. Por exemplo, se você colocar o bloco .catch() antes do bloco .then(), o bloco .then() ainda será executado. Como .catch() resolve a cadeia de promises (a menos que relance um erro), o .then() seguinte recebe undefined como argumento.
Quando você coloca o bloco .catch() antes do bloco .then(), qualquer erro lançado dentro do .then() não será capturado pelo .catch() precedente. Ele só será tratado se você adicionar outro bloco .catch() após ele.
Propagação de Rejeições
Você não precisa de um .catch() após cada .then(). Uma rejeição ignora todos os handlers de sucesso (o primeiro argumento de .then()) e percorre a cadeia até encontrar o primeiro .catch(). Isso permite que você escreva uma longa cadeia de etapas e trate qualquer falha em um único lugar ao final.
No exemplo abaixo, a rejeição ocorre logo no início, mas nenhum dos três callbacks .then() é executado — o controle salta diretamente para o único .catch():
Relançamento e Recuperação
Um handler .catch() realiza dois trabalhos dependendo do que faz:
- Recuperar — se retorna um valor (ou não retorna nada), a cadeia fica fulfilled novamente e o próximo
.then()é executado com esse valor. É assim que você fornece um valor alternativo. - Relançar — se
throw(ou retorna uma promise rejeitada), o erro continua propagando para o próximo.catch(). Use isso quando um handler não consegue lidar completamente com o erro e quer que um handler posterior conclua o trabalho.
Tratando Erros Específicos
JavaScript permite estratégias de tratamento de erros mais detalhadas, como filtrar erros com base em seu tipo ou nas circunstâncias específicas do erro. No exemplo a seguir, tratamos um TypeError. Um TypeError geralmente ocorre quando um valor não é do tipo esperado e, portanto, a operação desejada não pode ser realizada.
Boas Práticas para Tratamento de Erros em Promises
- Sempre retorne ou lance erros em blocos catch para garantir que os erros não sejam silenciosamente ignorados.
- Encadeie promises corretamente para garantir que os erros sejam capturados e tratados.
- Use blocos finally onde necessário para executar tarefas de limpeza, independentemente do resultado da promise.
Implementando um Bloco Finally
O método finally() é usado para executar um bloco de código após as promises serem resolvidas, independentemente do resultado.
Capturando Rejeições Não Tratadas
Se uma promise é rejeitada e nenhum .catch() jamais a trata, o erro é perdido silenciosamente — não há um try/catch envolvente como o código síncrono teria. Para evitar que bugs desapareçam, o ambiente dispara um evento global unhandledrejection ao qual você pode se inscrever. Isso é uma rede de segurança de último recurso para logging e relatórios, não um substituto para um .catch() real.
No navegador:
No Node.js, o equivalente é process.on('unhandledrejection', (reason) => { ... }).
Tratamento de Erros com async/await
async/await é construído sobre promises, portanto as mesmas rejeições ocorrem — mas você as captura com um bloco try/catch comum, que se lê como código síncrono. Um await em uma promise rejeitada lança uma exceção dentro da função async, e o try/catch a intercepta. Veja JavaScript: async/await para uma visão completa.
Um try/catch dentro de uma função async só captura erros de promises que você await. Se você chamar uma função que retorna uma promise sem await, sua rejeição escapa do try/catch — você deve ou usar await nela ou anexar um .catch().
Conclusão
O tratamento eficaz de erros em promises JavaScript é essencial para desenvolver aplicações web confiáveis e resilientes. Ao compreender o método .catch(), o segundo argumento de .then(), a propagação de rejeições, o relançamento e o gancho de limpeza .finally(), os desenvolvedores podem garantir que suas aplicações lidem com erros assíncronos de forma elegante e se recuperem em vez de travar. Ao trabalhar com async/await, envolva chamadas de promises aguardadas em blocos try/catch para um tratamento de erros de aparência síncrona, e mantenha um listener global unhandledrejection como rede de segurança para os casos que você perder.
Para aprofundar o conhecimento, continue com Encadeamento de Promises e a API de Promises.