Atualizado: 07/12/2024

Lidando com Erros e a Pilha de Chamadas de Funções - JavaScript

Quando um erro ocorre dentro de uma função e não é tratado, o interpretador de JavaScript sai dessa função e busca um tratador de erros no código externo. Veja o exemplo a seguir:

function A() {
    console.log("func A starts");
    callSomeFunc();
    console.log("func A ends");
}
A()
console.log("program ends");

Neste caso, a função A chama a função não definida callSomeFunc(). Assim, quando a função A é chamada, a execução é interrompida e o interpretador busca um tratador de erros no código externo. Como não há uma construção try..catch ao redor da chamada da função A, a execução do programa termina abruptamente. A saída no console será:

func A starts
Uncaught ReferenceError: callSomeFunc is not defined
    at A (index.html:11:2)
    at index.html:30:6

O mesmo se aplica a chamadas de funções aninhadas. Se um erro ocorre em uma função interna e não é tratado, o interpretador também sai para o contexto externo, a função externa. Se o erro também não for tratado na função externa, o interpretador continua buscando até encontrar um tratador de erros. Se não encontrar nenhum tratador de erro em nenhuma função nem no código global, o programa termina. Por exemplo:

function A() {
    console.log("func A starts");
    callSomeFunc();
    console.log("func A ends");
}
function B() {
    console.log("func B starts");
    A();
    console.log("func B ends");
}
function C() {
    console.log("func C starts");
    B();
    console.log("func C ends");
}
C();
console.log("program ends");

Aqui, a função C chama a função B, que por sua vez chama a função A, e esta tenta chamar a inexistente callSomeFunc. Como resultado, ocorre um erro na função A. Como a função A não tratou o erro, o interpretador busca um tratador na função B e depois na função C, e finalmente no contexto global. Mas, como em nenhum lugar o erro é tratado, a execução do programa é finalizada após o erro ocorrer:

func C starts
func B starts
func A starts
Uncaught ReferenceError: callSomeFunc is not defined
    at A (index.html:11:2)
    at B (index.html:16:2)
    at C (index.html:27:2)
    at index.html:31:1

Agora, vamos definir um tratador de erros em uma das funções, por exemplo, na função C:

function A() {
    console.log("func A starts");
    callSomeFunc();
    console.log("func A ends");
}
function B() {
    console.log("func B starts");
    A();
    console.log("func B ends");
}
function C() {
    console.log("func C starts");
    try {
        B();
    }
    catch {
        console.log("Error occured");
    }
    console.log("func C ends");
}

C();
console.log("program ends");

Com a introdução do tratador de erros, o interpretador primeiro busca um tratador na função A. Como o erro não é tratado lá, ele verifica no código envolvente na função B, e não encontrando, segue para a função C onde o erro é tratado, permitindo que o programa continue sua execução:

func C starts
func B starts
func A starts
Error occured
func C ends
program ends

Dessa forma, as funções A e B, que não trataram o erro, não são mais executadas após o erro ocorrer.

Propagando Erros pela Pilha de Chamadas de Funções

Às vezes, erros são tratados em algum lugar dentro das chamadas aninhadas de outras funções. Vamos considerar a seguinte situação:

// classe de um banco de dados fictício
class Database {
    constructor() {
        this.data = ["Tom", "Sam", "Bob"];
    }

    // método para obter dados
    getItem(index) {
        if (index >= 0 && index < this.data.length)
            return this.data[index];
        else  // se o índice for inválido, lançamos um erro
            throw new RangeError("Invalid index");
    }

    // método para abrir o banco de dados
    open() {
        console.log("Database has opened");
    }

    // método para fechar o banco de dados
    close() {
        console.log("Database has closed");
    }
}

// função para obter um objeto do banco de dados pelo índice
function get(index) {
    const db = new Database();
    db.open();  // simulamos a abertura do banco de dados
    try {
        return db.getItem(index);  // retornamos o elemento obtido
    } catch(err) {
        console.error(err);  // se ocorrer um erro, tratamos aqui
        throw err;  // lançamos o erro novamente para ser tratado mais acima na pilha
    } finally {
        db.close();  // simulamos o fechamento do banco de dados
    }
}

// função para exibir o resultado
function printResult() {
    try {
        const item = get(5);  // tentamos obter o elemento com índice 5
        console.log("Got from database:", item);  // exibimos o elemento obtido
    } catch(err) {
        console.error("Error during database retrieval:", err);  // tratamos o erro aqui
    }
}

printResult();

Este exemplo define uma classe Database simulada para interagir com um banco de dados contendo os nomes "Tom", "Sam" e "Bob". As funções open e close são utilizadas para simular a abertura e o fechamento do banco de dados, respectivamente. O método getItem retorna um elemento baseado no índice fornecido, mas lança um erro do tipo RangeError caso o índice seja inválido.

A função get é uma camada adicional que usa a classe Database para obter um item por índice, tratando os erros localmente e lançando-os novamente quando necessário. Isso permite que a função chamadora, printResult, seja informada sobre o erro, tratando-o apropriadamente.

O uso do bloco finally garante que o banco de dados seja fechado independentemente de erros ocorrerem, promovendo uma boa prática de gerenciamento de recursos. Essa abordagem é comum em aplicações que interagem com bases de dados, onde é crucial garantir que as conexões sejam fechadas após o uso para evitar vazamentos de recursos.

A saída do console será:

Database has opened
Error during database retrieval: RangeError: Invalid index at Database.getItem
Database has closed
Error during database retrieval: 
RangeError: Invalid index
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com