O que e JavaScript e como ele roda no navegador
O que e JavaScript de verdade: linguagem dinamica e single-threaded, como o engine compila seu codigo, o event loop e por que JS nao e o DOM.
Você abriu o DevTools pra entender por que um botão não respondia, leu "Uncaught TypeError" e fechou o console mais perdido do que entrou. Acontece. JavaScript é a linguagem que faz a página reagir ao clique, validar o formulário antes de mandar pro servidor e atualizar o carrinho sem recarregar nada — e mesmo assim quase ninguém para pra entender o que de fato acontece quando o navegador encontra um arquivo .js. A confusão piora porque o nome leva a erros bobos: JavaScript não é Java, nunca foi, e o "Script" no fim é praticamente uma piada de marketing dos anos 90.
Este guia explica o que é JavaScript de verdade, como o navegador executa o seu código (spoiler: não é "linha por linha"), e por que a diferença entre a linguagem e o DOM é a confusão que mais atrapalha quem está começando.
O que é JavaScript, sem o folclore
JavaScript é uma linguagem de programação dinâmica e single-threaded, criada em 1995 para rodar dentro do navegador. "Dinâmica" aqui quer dizer que os tipos são resolvidos em runtime: você não declara que x é um número, você só atribui um valor e a linguagem descobre o resto. Isso é flexível e também é a origem de metade dos bugs que você vai escrever na vida.
"Single-threaded" significa que existe uma única fila de execução — uma coisa de cada vez. Isso parece uma limitação absurda para uma linguagem que precisa lidar com cliques, requisições de rede e animações ao mesmo tempo, mas é exatamente aí que entra o event loop, que veremos adiante.
Sobre o nome: JavaScript não tem relação técnica com Java. Foi batizada assim porque Java estava na moda e a Netscape queria pegar carona no hype. A especificação real da linguagem chama-se ECMAScript, e quando alguém diz "ES2020" ou "ES6" está falando da versão dessa especificação. Na prática todo mundo diz JavaScript e segue a vida.
let nome = "Rafael"; // string
nome = 42; // agora é number, e ninguém reclama
const itens = [1, 2, 3];
Opinião sem rodeio: "vanilla JS" — JavaScript puro, sem framework — ainda importa muito. React, Vue e Svelte são ótimos, mas eles compilam para o mesmo JavaScript que roda no navegador, e quando algo quebra é nesse nível que você vai depurar. Quem entende a linguagem por baixo aprende qualquer framework em dias; quem só decorou React trava no primeiro erro estranho.
Como o navegador roda o seu JavaScript
Quando o navegador encontra um <script>, ele entrega o código para o JS engine — V8 no Chrome e no Node, SpiderMonkey no Firefox, JavaScriptCore no Safari. O engine não lê seu código "linha por linha como um interpretador burro", apesar de essa ser a explicação que circula em fóruns desde 2010.
O que acontece de verdade: o engine faz o parse do texto e gera uma representação intermediária (bytecode). Um interpretador começa a executar esse bytecode imediatamente, para você não esperar. Em paralelo, um compilador JIT (just-in-time) observa quais funções rodam muitas vezes — os "hot paths" — e recompila essas partes para código de máquina otimizado. É por isso que um loop executado um milhão de vezes fica mais rápido com o tempo: o engine percebeu que valia a pena otimizar.
Ou seja, JavaScript hoje é compilado, só que durante a execução, não antes. Chamar de "linguagem interpretada" não está totalmente errado, mas perde o ponto mais interessante e dá a falsa impressão de que é sempre lento. Não é.
Call stack, event loop e o tal do "assíncrono"
Aqui mora a parte que confunde quase todo mundo. Como a linguagem é single-threaded, ela tem uma única call stack: a pilha de funções que estão executando agora. Se uma função chama outra, ela empilha; quando retorna, desempilha. Simples.
O problema: se a call stack está ocupada, nada mais roda — nem o clique do usuário, nem o redesenho da tela. Se você fizer um cálculo que trava por três segundos, a página congela por três segundos. Já viu aquele "a página não está respondendo"? É a call stack presa.
A saída é não fazer o trabalho demorado na hora. Quando você dispara uma requisição (fetch), agenda um setTimeout ou espera um clique, o trabalho de espera é entregue ao navegador, fora da call stack. Quando termina, o resultado vai para uma fila de callbacks. O event loop é o mecanismo que fica olhando: "a call stack está vazia? Então pego o próximo callback da fila e empurro pra ela". É essa dança que permite uma linguagem de uma thread só parecer fazer várias coisas ao mesmo tempo.
console.log("1");
setTimeout(() => console.log("3"), 0);
console.log("2");
// imprime 1, 2, 3 — o setTimeout espera a stack esvaziar,
// mesmo com delay 0
Esse exemplo derruba muita gente em entrevista. O setTimeout com delay zero não roda imediatamente: ele vai para a fila e só executa quando a call stack estiver livre. Async/await e Promises são açúcar sintático por cima desse mesmo mecanismo — mais legíveis, mesma engrenagem por baixo.
JavaScript não é o DOM
Esta é a distinção que vale ouro. JavaScript, a linguagem, sabe sobre números, strings, arrays, funções, objetos. Ponto. Ela não sabe o que é um botão, uma <div> ou uma cor de fundo.
Tudo que mexe na página — document.querySelector, element.classList.add, addEventListener — não é JavaScript propriamente dito. É o DOM (Document Object Model), uma API que o navegador expõe para o seu código manipular a página. O engine executa a linguagem; o navegador fornece a ponte para a página. São duas camadas separadas, e por isso o mesmo JavaScript roda fora do navegador, onde o DOM simplesmente não existe.
Para entender como essa página inteira chega até o navegador antes mesmo do JavaScript entrar em cena — o caminho da requisição até a renderização — vale a leitura de como funciona uma página web, que cobre o pipeline completo de carregamento.
Onde mais o JavaScript roda
Em 2009 o Node.js pegou o engine V8, tirou do navegador e colocou no servidor. De repente dava para escrever back-end no mesmo idioma do front-end. Por isso hoje JavaScript roda em servidores, ferramentas de build, scripts de automação, funções serverless e até em microcontroladores. A linguagem é a mesma; o que muda são as APIs disponíveis — no navegador você tem o DOM e fetch, no Node você tem acesso ao sistema de arquivos e à rede em baixo nível.
Um detalhe prático que afeta performance: como você carrega o <script>. Sem atributo, o navegador para de montar a página, baixa e executa o script, e só então continua — bloqueante. Com defer, ele baixa em paralelo e executa só depois que o HTML terminou de ser parseado, na ordem em que aparecem. Com async, baixa em paralelo e executa assim que pronto, sem garantir ordem.
<script src="app.js" defer></script>
Para a maioria dos casos, defer é a escolha certa: não bloqueia a renderização e mantém a ordem. async serve para scripts independentes, tipo analytics, que não dependem de mais nada.
Se você quiser testar um pedaço de lógica — uma expressão regular, por exemplo — sem abrir o console, o testador de regex roda no mesmo motor JavaScript do navegador, então o comportamento é idêntico ao do seu código.
Perguntas frequentes
JavaScript é o mesmo que Java?
Não, e a semelhança termina nas quatro primeiras letras. Java é uma linguagem compilada, fortemente tipada, criada pela Sun; JavaScript é dinâmica e nasceu para o navegador. O nome foi uma jogada de marketing da Netscape em 1995 para aproveitar a popularidade do Java na época.
JavaScript é uma linguagem interpretada ou compilada?
As duas coisas, na prática. O engine interpreta o código para começar rápido e usa um compilador JIT para otimizar as partes que rodam com frequência, gerando código de máquina em runtime. Chamar de "puramente interpretada" está desatualizado faz mais de uma década.
Por que dizem que JavaScript é single-threaded se ele faz várias coisas ao mesmo tempo?
Porque ele tem uma única call stack — uma operação de cada vez. A sensação de paralelismo vem do event loop: tarefas demoradas (rede, timers) são delegadas ao navegador e seus resultados voltam por uma fila quando a stack está livre. A linguagem em si nunca executa duas coisas simultaneamente.
Preciso aprender JavaScript puro antes de um framework?
Vale muito a pena. Frameworks como React e Svelte compilam para JavaScript comum, e quando algo dá errado você depura nesse nível. Quem entende a linguagem por baixo aprende qualquer framework rápido; quem pula essa etapa costuma travar no primeiro erro fora do padrão.
A linguagem por baixo é o que vale
JavaScript é uma linguagem dinâmica e single-threaded, executada por um engine que compila seu código sob demanda, coordenada por um event loop que dá a ilusão de paralelismo, e que conversa com a página através do DOM — não confunda os dois. Entender essas camadas é o que separa quem copia stack traces do Google de quem lê o erro e sabe onde olhar. Frameworks vão e vêm; a engrenagem por baixo é a mesma há anos, e é nela que vale investir.
- 01 O que é software open source Open source não significa gratuito. Entenda o que a licença realmente define, as diferenças entre MIT, GPL e Apache, e como projetos open source se sustentam financeiramente.
- 02 PostgreSQL vs MySQL: diferenças práticas para quem precisa escolher Comparativo honesto entre PostgreSQL e MySQL: tipos nativos, JSONB vs JSON_EXTRACT, concorrência MVCC e extensões. Por que PostgreSQL como default faz sentido.