Tratando erros de Promise no Node.js: Como fazer isso corretamente

Erros em Promises podem interromper a execução do código se não forem tratados corretamente. Descubra como capturar e gerenciar erros de Promise no Node.js com as melhores práticas.

O que são Promises no Node.js?

Promises são objetos usados para representar a eventual conclusão ou falha de uma operação assíncrona. Quando você utiliza uma Promise no Node.js, ela pode estar em um dos três estados: pendente, cumprida ou rejeitada.

  • Pendente: A Promise ainda não foi resolvida ou rejeitada.
  • Cumprida: A Promise foi resolvida com sucesso, e o valor de retorno está disponível.
  • Rejeitada: A Promise falhou e foi rejeitada, geralmente devido a um erro.

Quando uma Promise é rejeitada, é fundamental tratá-la adequadamente, caso contrário, isso pode causar erros não tratados e falhas na execução do código. A boa prática é usar .catch(), async/await ou manipulação de erros adequada para garantir que todos os erros sejam capturados e tratados.

1. Usando .catch() para tratar erros em Promises

Uma das maneiras mais comuns de tratar erros em Promises no Node.js é utilizando o método .catch(). O .catch() é um manipulador de erro que captura qualquer erro gerado durante a execução da Promise.

Exemplo básico com .catch()

Aqui está um exemplo simples de como usar .catch() para capturar erros de uma Promise:

function fetchData() {
    return new Promise((resolve, reject) => {
        const success = false;
        if (success) {
            resolve('Dados recebidos com sucesso');
        } else {
            reject('Falha ao recuperar os dados');
        }
    });
}

fetchData()
    .then(result => {
        console.log(result);
    })
    .catch(err => {
        console.error('Erro:', err);
    });

Neste código, se a Promise for rejeitada, o erro será capturado no .catch() e exibido no console.

2. Usando async/await para lidar com erros de Promise

O uso de async/await torna o código assíncrono mais fácil de ler e entender. Com async/await, você pode usar a estrutura try/catch para capturar erros de Promessas de maneira mais intuitiva.

Exemplo com async/await e try/catch

Aqui está um exemplo de como usar async/await com try/catch para capturar erros de Promises:

async function fetchData() {
    try {
        const result = await new Promise((resolve, reject) => {
            const success = false;
            if (success) {
                resolve('Dados recebidos com sucesso');
            } else {
                reject('Falha ao recuperar os dados');
            }
        });
        console.log(result);
    } catch (err) {
        console.error('Erro:', err);
    }
}

fetchData();

Neste exemplo, a Promise é aguardada usando await, e caso ocorra um erro, ele é capturado pelo catch dentro do try/catch. O uso de async/await torna o código mais legível e mais fácil de debugar.

3. O que fazer quando a Promise não é tratada?

Se uma Promise é rejeitada e o erro não é tratado, o Node.js exibirá um unhandledRejection no console e, eventualmente, o processo será finalizado se não houver tratamento adequado para o erro.

Exemplo de erro não tratado

function fetchData() {
    return new Promise((resolve, reject) => {
        reject('Falha ao recuperar os dados');
    });
}

fetchData();  // Erro não tratado

No exemplo acima, a Promise é rejeitada, mas não há um .catch() ou try/catch para capturar o erro. Isso pode causar falhas no programa.

No Node.js, você pode usar o evento unhandledRejection para capturar erros não tratados globalmente.

process.on('unhandledRejection', (reason, promise) => {
    console.error('Erro não tratado:', reason);
    process.exit(1);  // Finaliza a aplicação após o erro
});

Este código vai capturar rejeições não tratadas de Promises e registrar o erro no console, garantindo que a aplicação não falhe sem uma explicação clara.

4. Rejeições em múltiplas Promises

Quando você tem várias Promises em execução simultânea, é importante garantir que cada Promise tenha seu próprio tratamento de erro. Uma forma comum de lidar com isso é usar Promise.all() para esperar que todas as Promises sejam resolvidas ou rejeitadas.

Exemplo de tratamento de múltiplas Promises com Promise.all():

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Dados de promise 1'), 1000);
});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => reject('Erro na promise 2'), 1500);
});

Promise.all([promise1, promise2])
    .then(results => {
        console.log('Resultados:', results);
    })
    .catch(err => {
        console.error('Erro:', err);
    });

No exemplo acima, a Promise.all() vai esperar até que todas as Promises sejam resolvidas ou rejeitadas. Se uma das Promises for rejeitada, o erro será capturado no .catch().

5. Conclusão

Lidar com erros de Promise de maneira adequada é essencial para garantir que sua aplicação Node.js seja resiliente e estável. Ao usar .catch() ou try/catch com async/await, você pode garantir que todos os erros sejam capturados e tratados adequadamente, evitando falhas inesperadas.

Além disso, sempre que possível, trate as Promessas rejeitadas globalmente usando o evento unhandledRejection, para evitar que erros não tratados causem problemas em produção.

As Promises no Node.js são amplamente utilizadas para gerenciar operações assíncronas e garantir que o código continue a execução sem bloqueios. Entretanto, é importante garantir que todos os erros que possam surgir durante a execução dessas Promises sejam adequadamente tratados.

Utilizar try/catch, .catch() e capturar erros globais com unhandledRejection são maneiras eficazes de garantir que a aplicação não falhe sem um tratamento adequado. Usar async/await melhora a legibilidade do código e facilita o tratamento de exceções assíncronas, ajudando a evitar falhas inesperadas no sistema.

Algumas aplicações:

  • Testar o comportamento de falhas em requisições HTTP assíncronas.
  • Validar consultas a banco de dados e interações com APIs externas.
  • Garantir que funções assíncronas não afetem o desempenho da aplicação quando rejeitadas.
  • Monitorar erros em tempo real com logs de rejeições de Promises.
  • Evitar que o código quebre ao usar Promises em larga escala.

Dicas para quem está começando

  • Sempre capture erros de Promises com .catch() ou try/catch para evitar falhas inesperadas.
  • Use async/await para escrever código assíncrono de maneira mais legível.
  • Registre todas as rejeições de Promises para saber quando e onde ocorreram erros.
  • Teste sua aplicação com unit tests para garantir que as Promessas estão sendo resolvidas ou rejeitadas corretamente.
  • Evite deixar Promises não tratadas no código de produção, isso pode causar falhas invisíveis.

Contribuições de João Gutierrez

Compartilhe este tutorial: Como lidar com erros de Promise no Node.js?

Compartilhe este tutorial

Continue aprendendo:

Como capturar erros não tratados no Node.js?

Erros não tratados podem causar falhas inesperadas em uma aplicação Node.js. Descubra como capturar e tratar esses erros para melhorar a robustez da sua aplicação.

Tutorial anterior

Como usar o ESLint para melhorar o código Node.js?

O ESLint é uma ferramenta poderosa para detectar e corrigir problemas no código JavaScript. Aprenda a configurar e usar o ESLint para melhorar a qualidade do código em suas aplicações Node.js.

Próximo tutorial