Erick Gabriel dos Santos AlvesFala, comunidade dev! 👋 Na Parte 1 desta série, saímos da superfície do HTML e descemos até a...
Fala, comunidade dev! 👋
Na Parte 1 desta série, saímos da superfície do HTML e descemos até a Arquitetura Multi-Processo do navegador. Vimos como a Main Thread e a placa de vídeo (GPU) brigam para colocar pixels na tela a 60 quadros por segundo.
Mas onde entra o JavaScript nessa história? Como o seu código em TypeScript vira eletricidade e lógica no processador do usuário? Hoje vamos abrir o capô do Motor V8 (Google Chrome / Node.js), entender o verdadeiro Event Loop e descobrir por que o Coletor de Lixo (Garbage Collector) pode ser o vilão silencioso da sua performance.
O seu navegador não entende JavaScript. Ele entende código de máquina (0s e 1s). O papel do Motor V8 (escrito em C++) é fazer essa tradução na velocidade da luz. Mas ele não faz isso de uma vez só. Ele usa uma estratégia de dois níveis:
.js e o transforma em uma árvore estruturada chamada Abstract Syntax Tree (AST).É aqui que a genialidade acontece: enquanto o seu código está rodando no Ignition, o V8 fica te "espionando". Ele anota quais funções você chama o tempo todo (ele chama isso de Hot Code).
calcularFrete(peso, distancia) milhares de vezes sempre passando números inteiros, ele pega esse Bytecode e joga para o TurboFan. O TurboFan compila isso diretamente para Código de Máquina altamente otimizado. A sua função passa a rodar absurdamente rápido.O Perigo do "Deoptimization": Se, do nada, você chamar a mesma função
calcularFrete('muito pesado', 100)passando umaStringem vez de um número, o TurboFan entra em pânico. Ele percebe que a premissa de otimização falhou, joga o código de máquina no lixo e volta a rodar a função no Interpretador lento (Ignition). Isso se chama Deoptimization. Manter os tipos dos seus objetos e variáveis consistentes (alô, TypeScript!) não é só para o desenvolvedor ler, é para o TurboFan não "desotimizar" o seu código em produção.
Você já deve ter ouvido que o JS é Single-Threaded (faz uma coisa por vez). Mas então, como fazemos uma chamada HTTP (fetch) sem a tela congelar por 3 segundos?
A resposta: O fetch, o setTimeout e o DOM não são JavaScript.
Eles são Web APIs, funcionalidades escritas em C++ pelo navegador, que o JS tem permissão para acionar.
O fluxo real é este:
setTimeout na Call Stack (Pilha de Chamadas).É aqui que entra o Event Loop: ele é um vigia que fica olhando para a Call Stack. Quando ela está totalmente vazia, ele pega o primeiro item da Task Queue e joga na Call Stack para o V8 executar.
Aqui é onde 90% dos bugs de performance assíncrona nascem. Na verdade, existem DUAS filas esperando para entrar na Call Stack:
setTimeout, setInterval e eventos de clique..then, async/await) e o MutationObserver.A Regra de Ouro do Event Loop: O Event Loop nunca vai olhar para a fila comum (Macrotasks) ou para a renderização da tela enquanto a Fila VIP (Microtasks) não estiver 100% vazia.
O Bug Infinito: Se você criar uma função recursiva que gera Promises infinitamente, você trava a aba do navegador para sempre. O Event Loop vai ficar preso esvaziando a fila VIP de Microtasks, e o navegador nunca terá a chance de pintar a tela (Render Pipeline) ou capturar um clique do usuário.
Você cria milhares de objetos, arrays e variáveis no seu código. Quando você não precisa mais deles, quem limpa a memória (RAM)? O Garbage Collector (GC).
O V8 usa um algoritmo chamado Mark and Sweep (Marcar e Varrer). Ele começa da raiz (window) e vai varrendo todas as variáveis. O que ele não consegue alcançar (um objeto que você tirou a referência, por exemplo), ele marca como lixo e devolve a memória para o SO.
O problema crítico: Para limpar a memória com segurança, o V8 precisa pausar a execução do seu JavaScript. Isso se chama evento Stop-The-World.
Se você programa mal e cria arrays de 10.000 posições o tempo todo dentro de um loop, você enche a memória rapidamente. O Garbage Collector vai ter que pausar a sua Main Thread a cada 2 segundos para limpar o lixo. Resultado? A tela do usuário dá pequenos "soquinhos" ou engasgos (Jank).
Entender a plataforma tira você do escuro.
Quando o seu código Front-end está lento, a culpa raramente é do framework. A culpa é do código mudando o formato dos objetos (Deoptimization no TurboFan), abusando da Call Stack (bloqueando o Event Loop), ou criando lixo demais na memória (forçando o Garbage Collector a pausar a tela).
Da próxima vez que for escrever um loop pesado, lembre-se: o TurboFan está te observando, o Event Loop está esperando, e o Garbage Collector está pronto para cobrar a conta da memória.
Gostaram de descer até o nível do C++ do navegador? Qual desses conceitos arquiteturais foi a maior surpresa para vocês? Deixem nos comentários! 👇