Atualizado: 21/06/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Lidando com Erros e a Pilha de Chamadas de Funções em 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];
    // se o índice for inválido, lançamos um erro
    else 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