A call stack tem tamanho limitado. O limite padrão varia conforme o engine — o V8 do Chrome costuma permitir cerca de 10.000–15.000 frames, enquanto o SpiderMonkey do Firefox tem limite similar. Se você continuar empilhando funções sem removê-las, eventualmente ficará sem espaço. Isso é chamado de stack overflow (estouro de pilha), e o JavaScript lança um RangeError quando isso acontece.
snippettext
┌─────────────────────────────────────────────────────────────────────────┐│ STACK OVERFLOW │├─────────────────────────────────────────────────────────────────────────┤│ ││ ERRADO: Sem Caso Base CERTO: Com Caso Base ││ ──────────────────── ───────────────────── ││ ││ function count() { function count(n) { ││ count() // Para sempre! if (n <= 0) return // Pare! ││ } count(n - 1) ││ } ││ ││ Pilha cresce para sempre... Pilha cresce, depois encolhe ││ ┌─────────┐ ┌─────────┐ ││ │ count() │ │ count(0)│ ← Retorna ││ ├─────────┤ ├─────────┤ ││ │ count() │ │ count(1)│ ││ ├─────────┤ ├─────────┤ ││ │ count() │ │ count(2)│ ││ ├─────────┤ └─────────┘ ││ │ .... │ ││ └─────────┘ ││ 💥 CRASH! ✓ Sucesso! ││ │└─────────────────────────────────────────────────────────────────────────┘
A armadilha: funções recursivas sem condição de parada adequada vão travar seu programa. A causa mais comum é recursão infinita — uma função que chama a si mesma para sempre sem caso base.
O Erro Clássico: Caso Base Ausente
snippetJavaScript
// ❌ RUIM: Isso vai travar!function countdown(n) { console.log(n); countdown(n - 1); // Chama a si mesma para sempre!} countdown(5);
O que acontece:
snippettext
Pilha: [ countdown(5) ]Pilha: [ countdown(4), countdown(5) ]Pilha: [ countdown(3), countdown(4), countdown(5) ]Pilha: [ countdown(2), countdown(3), countdown(4), countdown(5) ]... continua crescendo para sempre ...💥 CRASH: Maximum call stack size exceeded
A Correção: Adicionar um Caso Base
snippetJavaScript
// ✅ BOM: Isso funciona corretamentefunction countdown(n) { if (n <= 0) { console.log("Done!"); return; // ← CASO BASE: Pare aqui! } console.log(n); countdown(n - 1);} countdown(5);// Saída: 5, 4, 3, 2, 1, Done!
O que acontece agora:
snippettext
Pilha: [ countdown(5) ]Pilha: [ countdown(4), countdown(5) ]Pilha: [ countdown(3), countdown(4), countdown(5) ]Pilha: [ countdown(2), countdown(3), ..., countdown(5) ]Pilha: [ countdown(1), countdown(2), ..., countdown(5) ]Pilha: [ countdown(0), countdown(1), ..., countdown(5) ] ↑ Caso base alcançado! Começar a retornar.Pilha: [ countdown(1), ..., countdown(5) ]Pilha: [ countdown(2), ..., countdown(5) ]... pilha desenrola ...Pilha: [ countdown(5) ]Pilha: [ vazia ]✅ Programa completa com sucesso
Mensagens de Erro por Navegador
| Navegador | Mensagem de Erro |
|---|
| Chrome | RangeError: Maximum call stack size exceeded |
| Firefox | InternalError: too much recursion (não padrão) |
| Safari | RangeError: Maximum call stack size exceeded |
O Firefox usa InternalError, que é um tipo de erro não padrão específico do engine SpiderMonkey. Chrome e Safari usam o RangeError padrão.
Causas Comuns de Stack Overflow
1. Recursão Infinita (Sem Caso Base)
snippetJavaScript
function loop() { loop();}loop(); // 💥 Crash!
2. Caso Base Nunca Alcançado
snippetJavaScript
function countUp(n) { if (n >= 1000000000000) return; // Muito longe! countUp(n + 1);}countUp(0); // 💥 Crash antes de alcançar o caso base
3. Recursão Acidental em Setters
snippetJavaScript
class Person { set name(value) { this.name = value; // Chama o setter de novo! Loop infinito! }} const p = new Person();p.name = "Alice"; // 💥 Crash! // Correção: use outro nome de propriedadeclass PersonFixed { set name(value) { this._name = value; }}
4. Chamadas Circulares Entre Funções
snippetJavaScript
function a() { b(); }function b() { a(); } // a chama b, b chama a, para sempre! a(); // 💥 Crash!
Dicas de prevenção:
- Sempre defina um caso base claro para funções recursivas
- Garanta que cada chamada recursiva se aproxima do caso base
- Considere usar iteração (loops) em vez de recursão para casos simples
- Cuidado com setters de propriedade — use nomes internos diferentes