Back

Interaction to Next Paint (INP): O Guia Definitivo de Otimização (2025)

Em março de 2024, o Google substituiu oficialmente o First Input Delay (FID) pelo Interaction to Next Paint (INP) como uma Core Web Vital. Isso não foi apenas uma troca menor de métricas; foi uma mudança fundamental na forma como medimos a responsividade da web.

Por anos, desenvolvedores otimizaram para o primeiro clique. Mas os usuários não clicam apenas uma vez. Eles digitam, alternam, arrastam e esperam que a interface responda instantaneamente todas as vezes. O FID media apenas a primeira impressão. O INP mede todo o relacionamento.

Se você notou que seu "Total Blocking Time" (TBT) está alto, ou sua pontuação no Lighthouse é verde, mas seus usuários reais reclamam de uma UI "travada", este guia é para você. Vamos mergulhar fundo na mecânica da thread principal do navegador para entender por que as interações atrasam e como corrigir isso.

A Anatomia de uma Interação

Para otimizar o INP, você deve entender o que acontece quando um usuário clica em um botão. Não é instantâneo. O navegador passa por três fases distintas:

  1. Input Delay (Atraso de Entrada): O tempo desde o toque do usuário até o navegador começar a executar o manipulador de eventos. Muitas vezes causado por outras tarefas bloqueando a thread principal (ex: um processo de hydration rodando exatamente quando o usuário clica).
  2. Processing Time (Tempo de Processamento): O tempo que leva para rodar seus callbacks de eventos (atualizações de estado do React, manipulação do DOM, lógica complexa).
  3. Presentation Delay (Atraso de Apresentação): O tempo desde que seu código termina de rodar até o navegador realmente pintar o próximo frame na tela.

INP = Input Delay + Processing Time + Presentation Delay

A maioria dos desenvolvedores foca apenas no passo 2 (otimizar seu código). No entanto, uma grande parte das pontuações ruins de INP vem dos passos 1 e 3.

Por que console.time() Está Mentindo para Você

Você pode envolver seu manipulador de clique em um console.time() e ver que ele roda em 20ms. "Ótimo!", você pensa, "Meu código é rápido." Mas sua pontuação INP reporta 400ms. Por quê?

Porque console.time() mede apenas a execução do JavaScript. Ele não mede o custo de renderização.

Se sua atualização de estado React de 20ms desencadeia uma re-renderização de toda a árvore de componentes, forçando o navegador a recalcular estilos e layout para 5.000 nós DOM, esse "layout thrashing" acontece depois que seu JavaScript termina, mas antes da próxima pintura. Isso é Presentation Delay, e conta contra seu INP.

Estratégia 1: Cedendo à Thread Principal (Yielding)

A regra de ouro da responsividade é: Não monopolize a thread principal.

Se você tem uma tarefa de longa duração (ex: processar um grande array de dados), o navegador fica "congelado". Ele não pode lidar com novas entradas ou pintar a tela. A solução é dividir tarefas longas em pedaços menores e "ceder" (yield) o controle de volta ao navegador entre eles.

O Jeito Antigo: setTimeout

function processData(items) { if (items.length === 0) return; // Processar um item doHeavyWork(items[0]); // Agendar o resto para depois setTimeout(() => { processData(items.slice(1)); }, 0); }

Isso funciona, mas setTimeout tem um atraso mínimo (frequentemente 4ms ou mais) e não prioriza tarefas de forma inteligente.

O Jeito Moderno: scheduler.yield()

A nova API scheduler.yield() (atualmente em origin trial ou polyfilled) permite que você ceda à thread principal e retome a execução imediatamente sem a penalidade do setTimeout.

async function processData(items) { for (const item of items) { doHeavyWork(item); // Ceder à thread principal para deixar o navegador lidar com inputs/pintura // Isso verifica se há input de usuário pendente! await scheduler.yield(); } }

Isso muda o jogo. Diz ao navegador: "Vou pausar por um microssegundo. Se tiver um clique esperando, lide com ele agora. Se não, continuarei."

Estratégia 2: Otimizando o Presentation Delay

Se seu JavaScript é rápido, mas a pintura é lenta, você tem um problema de renderização.

  1. Reduzir o Tamanho do DOM: Uma árvore DOM massiva aumenta o custo de Recálculo de Estilo e Layout. Virtualize listas longas.
  2. CSS Containment: Use a propriedade content-visibility: auto para pular a renderização de conteúdo fora da tela.
  3. Evitar Layout Thrashing: Não leia propriedades de layout (como offsetHeight) imediatamente após escrevê-las. Isso força o navegador a realizar um cálculo de layout síncrono.

Estratégia 3: Feedback Imediato (UI Otimista)

Psicologicamente, um usuário sente que um app é "lento" se não vê uma reação. Tecnicamente, o INP mede o tempo até a próxima pintura.

Se você tem uma operação pesada (como uma chamada de API), pinte algo imediatamente.

Padrão Ruim:

button.addEventListener('click', async () => { const data = await fetchData(); // Espera pela rede... renderData(data); // ...então pinta. });

O INP inclui o tempo de espera da rede!

Padrão Bom:

button.addEventListener('click', () => { showSpinner(); // Pinta imediatamente! O INP para de medir aqui. fetchData().then(data => { renderData(data); hideSpinner(); }); });

Ao mostrar um spinner ou um estado ativo imediatamente, você "completa" a interação da perspectiva do navegador. A requisição de rede subsequente e a renderização final são tarefas separadas que não prejudicam sua pontuação INP.

Conclusão

O INP é uma métrica rigorosa, mas nos força a construir software melhor. Ele nos empurra para longe de arquiteturas "pesadas em JS, bloqueadoras de thread principal" em direção a designs "assíncronos, que cedem controle e são responsivos".

Comece perfilando suas interações mais lentas. É a lógica? A renderização? Ou apenas uma thread principal ocupada? Uma vez que você identifique o gargalo, as ferramentas—scheduler.yield(), virtualização de DOM e atualizações de UI otimistas—estão prontas para você usar.

Faça seu site parecer instantâneo. Seus usuários (e seus rankings de SEO) agradecerão.

Web PerformanceCore Web VitalsJavaScriptOptimizationINP

Explore ferramentas relacionadas

Experimente estas ferramentas gratuitas do Pockit