Tratamento de erros no Node.js

Erros no Node.js são tratados por meio de exceções.

Criando exceções

Uma exceção é crianda usando a palavra reservada throw:

throw value

Assim que o JavaScript executa essa linha, o fluxo normal do programa é parado e o controle é retomado pelo tratamento de exceção mais próximo.

Normalmente no código client-side o value pode ser qualquer valor JavaScript, incluindo uma string, um número ou um objeto.

No Node.js, nós não lançamos strings, só lançamos objetos de erro.

Objetos de erro

Um objeto de erro é um objeto que é uma instância do objeto Error, ou que extenda a classe Error, fornecida pelo módulo nativo Error:

throw new Error('Ran out of coffee')

ou

class NotEnoughCoffeeError extends Error {
// ...
}
throw new NotEnoughCoffeeError()

Tratando exceções

Um bloco try/catch é um tratador de exceções.

Qualquer exceção lançada nas linhas que incluem o bloco try serão tratadas no bloco catch correspondente:

try {
// linhas de código
} catch (e) {}

e nesse excemplo é o valor da exceção.

Você pode adicionar múltiplos blocos, que podem tratar diferentes tipos de erros.

Pegando exceções não capturadas

Se uma exceção não capturada for lançada durante a execução do seu programa, ele irá crashar.

Para resolver isso, escute o evento uncaughtException no objeto process:

process.on('uncaughtException', err => {
console.error('There was an uncaught error', err)
process.exit(1) // obrigatório (conforme as docs do Node.js)
})

Você não precisa importar o módulo nativo process, ele é automaticamente injetado.

Exceções com promises

Usando promises você pode encadear diferentes operações, e tratar erros no final:

doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => console.error(err))

Como você sabe quando o erro ocorreu? Você na verdade não sabe, mas você pode tratar erros em cada uma das funções que chamar (doSomethingX), e dentro do catch lançar um novo erro, que chamará o catch exterior:

const doSomething1 = () => {
//...
try {
//...
} catch (err) {
//... trata o erro localmente
throw new Error(err.message)
}
//...
}

Para ser possível tratar erros localmente sem tratá-los na função que chamamos, nós podemos quebar a corrente, você pode criar uma função em cada then e processar a exceção:

doSomething1()
.then(() => {
return doSomething2().catch(err => {
// trata o erro
throw err // quebre a corrente!
})
})
.then(() => {
return doSomething2().catch(err => {
// trata o erro
throw err // quebra a corrente!
})
})
.catch(err => console.error(err))

Tratando erros com async/await

Usando async/await, você ainda precisa tratar erros, e você pode fazer isso dessa forma:

async function someFunction() {
try {
await someOtherFunction()
} catch (err) {
console.error(err.message)
}
}