Debugging eficiente
Nesta aula, você vai dominar técnicas profissionais de debugging em JavaScript, indo além do console.log. Exploraremos métodos avançados do console, breakpoints no DevTools, interpretação de stack traces e a instrução debugger, com exemplos práticos e exercícios para consolidar o aprendizado.
Depurar código é uma habilidade essencial para qualquer desenvolvedor. Embora o console.log seja o método mais comum e rápido, ele tem limitações: polui o código, exige remoção posterior e nem sempre fornece o contexto necessário. Nesta aula, você aprenderá técnicas profissionais de debugging em JavaScript, usando ferramentas do navegador e métodos avançados do console para identificar e corrigir bugs de forma mais eficiente.
Vamos explorar desde os métodos menos conhecidos do console até o uso de breakpoints e a análise de stack traces, passando pela instrução debugger. Ao final, você terá um arsenal completo para depurar qualquer aplicação JavaScript, seja no front-end ou no back-end (Node.js).
console além do log
O objeto console oferece muito mais do que log. Métodos como info, warn e error permitem categorizar mensagens, facilitando a filtragem no DevTools. Por exemplo, console.error exibe a mensagem com um ícone vermelho e inclui um stack trace, essencial para erros. Já console.warn mostra um aviso amarelo, útil para alertas não críticos.
Além disso, console.table formata arrays e objetos em uma tabela legível, ideal para inspecionar dados complexos. console.group e console.groupCollapsed organizam logs em grupos expansíveis, mantendo o console limpo. console.time e console.timeEnd medem a duração de operações, essenciais para análise de desempenho. E console.assert só exibe uma mensagem se uma condição for falsa, permitindo testes rápidos.
// Exemplo de uso dos métodos do console
const usuarios = [
{ nome: 'Ana', idade: 25 },
{ nome: 'Bruno', idade: 30 },
{ nome: 'Carla', idade: 28 }
];
console.info('Lista de usuários:');
console.table(usuarios);
console.warn('Atenção: dados de teste!');
console.time('loop');
for (let i = 0; i < 1000000; i++) { /* simulação */ }
console.timeEnd('loop');
console.assert(usuarios.length === 3, 'Número de usuários diferente de 3');
console.group('Detalhes do primeiro usuário');
console.log('Nome:', usuarios[0].nome);
console.log('Idade:', usuarios[0].idade);
console.groupEnd();Breakpoints no DevTools
Breakpoints são pontos de parada no código que interrompem a execução em um momento específico, permitindo inspecionar variáveis, chamar funções e avançar passo a passo. Diferente do console.log, os breakpoints não exigem alteração no código e podem ser adicionados diretamente no painel Sources do DevTools. Basta clicar no número da linha desejada para criar um breakpoint.
Além dos breakpoints tradicionais, o DevTools oferece breakpoints condicionais, que só pausam quando uma expressão é verdadeira, e breakpoints de exceção, que pausam quando um erro é lançado. Durante a pausa, você pode inspecionar o escopo, observar variáveis específicas e até avaliar expressões no console. Isso dá um controle muito maior sobre a depuração, especialmente em fluxos complexos.
// Exemplo de código para testar breakpoints
function calcularTotal(produtos) {
let total = 0;
for (let produto of produtos) {
total += produto.preco; // Adicione um breakpoint aqui
}
return total;
}
const carrinho = [
{ nome: 'Notebook', preco: 3000 },
{ nome: 'Mouse', preco: 150 },
{ nome: 'Teclado', preco: 200 }
];
console.log(calcularTotal(carrinho));Stack traces
Quando um erro é lançado, o JavaScript gera um stack trace, que é a sequência de chamadas de função que levaram ao erro. Essa informação é crucial para rastrear a origem do problema, especialmente em aplicações com muitas funções aninhadas. Você pode ver o stack trace no console quando um erro não é tratado, ou capturá-lo programaticamente usando console.trace().
Analisar um stack trace envolve ler de baixo para cima: a primeira linha indica a função onde o erro ocorreu, e as linhas seguintes mostram as chamadas que levaram até lá. Isso ajuda a identificar se o erro é causado por dados inválidos, chamadas incorretas ou problemas em funções externas. Em aplicações complexas, um stack trace bem interpretado pode economizar horas de depuração.
function funcaoA() {
funcaoB();
}
function funcaoB() {
funcaoC();
}
function funcaoC() {
console.trace('Rastreando chamadas');
throw new Error('Erro proposital');
}
try {
funcaoA();
} catch (erro) {
console.error(erro.stack);
}debugger
A instrução debugger é uma ferramenta que, quando executada, pausa a execução do código no ponto exato, desde que o DevTools esteja aberto. É como um breakpoint programático, mas adicionado no código fonte. Isso é útil quando você precisa pausar em uma condição específica ou quando está depurando código que não pode ser facilmente modificado no DevTools (por exemplo, em Node.js).
Para usar, basta inserir a palavra debugger; no local desejado. Quando o interpretador chegar lá, o depurador será ativado. No Node.js, você pode usar junto com o inspetor (por exemplo, node inspect app.js). Lembre-se de remover as instruções debugger antes de publicar o código, pois elas podem causar pausas indesejadas em produção.
function processarDados(dados) {
// Simulando processamento complexo
let resultado = dados.map(item => item * 2);
debugger; // Pausa aqui para inspecionar 'resultado'
return resultado;
}
const dados = [1, 2, 3, 4];
console.log(processarDados(dados));Boas práticas e observações finais
Para uma depuração eficiente, combine várias técnicas: use console.table para dados tabulares, breakpoints para fluxos complexos e stack traces para erros inesperados. Evite deixar logs de depuração no código final; se precisar, use um sistema de logging condicional. No DevTools, familiarize-se com os atalhos (F8 para pausar, F10 para avançar).
Lembre-se de que a depuração é uma habilidade que melhora com a prática. Sempre que encontrar um bug, tente entender a causa raiz em vez de aplicar correções superficiais. Use os breakpoints para explorar o estado das variáveis e o fluxo de execução, e os stack traces para rastrear a origem do problema. Com essas ferramentas, você se tornará um desenvolvedor muito mais produtivo.
Referências
- MDN: Console
- Chrome DevTools: JavaScript Debugging
- MDN: debugger
- MDN: Error.prototype.stack
- Node.js: Debugging Guide
- MDN: console.trace()
Exercícios
- Escreva uma função que receba um array de números e retorne a soma, mas use
console.tablepara exibir o array e umconsole.time/console.timeEndpara medir o tempo de execução. Depois, execute no console do navegador e observe a saída.✓ Resposta:function somarNumeros(numeros) { console.table(numeros); console.time('soma'); let total = 0; for (let num of numeros) { total += num; } console.timeEnd('soma'); return total; } somarNumeros([1, 2, 3, 4, 5]); - Crie um código que lance uma exceção dentro de uma função chamada por outra, e use
console.trace()dentro da função interna para rastrear a sequência de chamadas. Observe o stack trace no console.✓ Resposta:function externa() { interna(); } function interna() { console.trace('Debug do stack trace'); throw new Error('Erro na função interna'); } try { externa(); } catch (e) { console.error(e.stack); } - Explique a diferença entre
console.logeconsole.errorno contexto de depuração. Dê um exemplo de quando usar cada um.✓ Resposta:console.logé para mensagens gerais de depuração, sem ênfase especial.console.errorexibe a mensagem em vermelho e inclui um stack trace, sendo ideal para erros e situações excepcionais. Useconsole.logpara acompanhar o fluxo normal econsole.errorpara capturar falhas, facilitando a filtragem no console. - Descreva um cenário em que você preferiria usar um breakpoint condicional em vez de um
console.logdentro de um loop. Implemente esse cenário com um exemplo de código e explique como você configuraria o breakpoint.✓ Resposta: Se você tem um loop que itera 1000 vezes e quer inspecionar apenas quando o índice for 500, um breakpoint condicional evita parar em todas as iterações. No DevTools, você adiciona um breakpoint na linha do loop e clica com o botão direito para editar a condição, inserindoi === 500. Exemplo:for (let i = 0; i < 1000; i++) { // breakpoint condicional aqui: i === 500 console.log(i); } - Escreva um trecho de código com a instrução
debuggere explique como você a usaria para inspecionar variáveis em um cenário de depuração no navegador.✓ Resposta:
Com o DevTools aberto, a execução pausa na linha dofunction calcularDesconto(preco, percentual) { let desconto = preco * (percentual / 100); debugger; // Pausa aqui para inspecionar 'preco', 'percentual' e 'desconto' return preco - desconto; } console.log(calcularDesconto(100, 10));debugger, permitindo passar o mouse sobre as variáveis para ver seus valores, ou avaliar expressões no console.