Jank e o Ciclo de Renderização
Você tem uma tabela/grid complexa com dezenas de linhas e colunas customizadas. Usuários relatam que, ao interagir com filtros ou redimensionar blocos, a interface sofre com travamentos perceptíveis (*jank* e perda de frames).
Problema
Você tem uma tabela/grid complexa com dezenas de linhas e colunas customizadas. Usuários relatam que, ao interagir com filtros ou redimensionar blocos, a interface sofre com travamentos perceptíveis (jank e perda de frames).
Ao abrir o Chrome DevTools (aba Performance), você grava uma interação e identifica várias barras vermelhas de Long Tasks (tarefas bloqueando a main thread por mais de 50ms) com dezenas de avisos de:
Forced Reflow / Layout Thrashing
Ao investigar o código de uma diretiva que calcula o layout dos elementos, você encontra uma lógica equivalente a esta:
elements.forEach(elementRef => {
const currentHeight = elementRef.nativeElement.offsetHeight;
elementRef.nativeElement.style.height = `${currentHeight + 10}px`;
});
Forced Reflow
Por padrão, o navegador é "preguiçoso" (lazy) para economizar processamento:
1. Quando você altera um estilo (element.style.height = ...), o navegador não recalcula a geometria da tela imediatamente. Ele apenas marca a árvore de layout como "suja" (invalidated/dirty) e guarda a intenção para recalcular tudo de uma vez só no final do frame, antes de pintar na tela.
2. O problema acontece quando, na iteração seguinte do loop, o código faz uma leitura geométrica (element.offsetHeight, offsetWidth, getBoundingClientRect(), etc.).
3. O navegador pensa: "O layout atual está desatualizado porque houve uma alteração de estilo agora há pouco, mas o código JavaScript está me exigindo a altura exata e atualizada neste exato milissegundo."
4. O motor é forçado a pausar a execução do JavaScript e rodar um cálculo de layout completo (Reflow) imediatamente para poder responder àquela linha.
Se você tiver 100 itens no loop alternando leitura e escrita, em vez de 1 único Reflow no final do frame, o navegador executa 100 Reflows síncronos forçados. É essa repetição síncrona que bloqueia a main thread e gera o jank.
Como melhorar isso?
A regra de ouro da plataforma web para evitar Layout Thrashing é a separação estrita entre fases de Leitura (Read) e Escrita (Write):
// READ
const heights = elements.map(elementRef => { return elementRef.nativeElement.offsetHeight; });
//WRITE
elements.forEach((elementRef, index) => {
const newHeight = heights[index] + 10; elementRef.nativeElement.style.height = `${newHeight}px`;
});
Sempre que precisar manipular geometria no DOM dentro de componentes ou diretivas, pergunte-se primeiro: "Isso pode ser resolvido com CSS puro (Flexbox, Grid, calc() , aspect-ratio ou variáveis CSS)?". Se o CSS resolver, o navegador faz o cálculo na camada nativa sem tocar na thread de JavaScript.