Otimizar a interação com a próxima exibição

Saiba como otimizar a Interação com a próxima exibição do seu site.

Publicado em: 19 de maio de 2023. Última atualização: 2 de setembro de 2025

A Interação com a próxima exibição (INP) é uma métrica estável das Core Web Vitals que avalia a capacidade de resposta geral de uma página às interações do usuário, observando a latência de todas as interações qualificadas que ocorrem durante a vida útil da visita de um usuário a uma página. O valor final da INP é a interação mais longa observada, ignorando os valores atípicos.

Para oferecer uma boa experiência ao usuário, os sites devem buscar uma Interaction to Next Paint de 200 milissegundos ou menos. Para atingir essa meta na maioria dos casos, um bom limite é o 75º percentil de carregamentos de página, segmentado em dispositivos móveis e computadores.

Valores bons de INP são de 200 milissegundos ou menos, valores ruins são maiores que 500 milissegundos, e qualquer valor entre eles precisa de melhoria.
Limiares de INP

Dependendo do site, pode haver poucas ou nenhuma interação, como páginas com principalmente texto e imagens com poucos ou nenhum elemento interativo. Ou, no caso de sites como editores de texto ou jogos, pode haver centenas, até milhares, de interações. Em ambos os casos, quando há um INP alto, a experiência do usuário fica em risco.

Leva tempo e esforço para melhorar o INP, mas a recompensa é uma experiência do usuário melhor. Neste guia, vamos explorar um caminho para melhorar o INP.

Descubra o que está causando um INP ruim

Antes de corrigir interações lentas, você precisa de dados para saber se o INP do seu site é ruim ou precisa de melhorias. Depois de ter essas informações, você pode ir para o laboratório e começar a diagnosticar interações lentas e trabalhar em uma solução.

Encontrar interações lentas no campo

O ideal é que sua jornada de otimização do INP comece com dados de campo. Na melhor das hipóteses, os dados de campo de um provedor de monitoramento de usuários reais (RUM, na sigla em inglês) fornecem não apenas o valor de INP de uma página, mas também dados contextuais que destacam qual interação específica foi responsável pelo valor de INP, se a interação ocorreu durante ou após o carregamento da página, o tipo de interação (clique, pressionamento de tecla ou toque) e outras informações valiosas.

Se você não estiver usando um provedor de RUM para receber dados de campo, o guia de dados de campo do INP recomenda usar o PageSpeed Insights para ver os dados do Chrome User Experience Report (CrUX) e preencher as lacunas. A CrUX é o conjunto de dados oficial do programa Core Web Vitals e oferece um resumo de alto nível das métricas de milhões de sites, incluindo a INP. No entanto, a CrUX geralmente não fornece os dados contextuais que você receberia de um provedor de RUM para ajudar na análise de problemas. Por isso, ainda recomendamos que os sites usem um provedor de RUM sempre que possível ou implementem a própria solução de RUM para complementar o que está disponível no CrUX.

Diagnosticar interações lentas no laboratório

O ideal é começar a testar no laboratório quando você tiver dados de campo que sugiram interações lentas. Na ausência de dados de campo, há algumas estratégias para identificar interações lentas no laboratório. Essas estratégias incluem seguir fluxos de usuários comuns e testar interações ao longo do caminho, além de interagir com a página durante o carregamento (quando a linha de execução principal costuma estar mais ocupada) para identificar interações lentas nessa parte crucial da experiência do usuário.

Otimizar interações

Depois de identificar uma interação lenta e reproduzi-la manualmente no laboratório, a próxima etapa é otimizá-la.

As interações podem ser divididas em três subpartes:

  1. O atraso de entrada, que começa quando o usuário inicia uma interação com a página e termina quando os callbacks de evento da interação começam a ser executados.
  2. A duração do processamento, que consiste no tempo que os callbacks de eventos levam para ser concluídos.
  3. O atraso de apresentação, que é o tempo necessário para o navegador apresentar o próximo frame que contém o resultado visual da interação.
Um exemplo de interação na linha de execução principal. O usuário faz uma entrada enquanto as tarefas de bloqueio são executadas. A entrada é atrasada até que essas tarefas sejam concluídas. Depois disso, os manipuladores de eventos pointerup, mouseup e click são executados. Em seguida, o trabalho de renderização e pintura é iniciado até que o próximo frame seja apresentado.
O ciclo de uma interação. Um atraso de entrada ocorre até que os manipuladores de eventos comecem a ser executados, possivelmente causado por fatores como tarefas longas na linha de execução principal. Em seguida, as callbacks do manipulador de eventos da interação são executadas, e ocorre um atraso antes da apresentação do próximo frame.

A soma dessas três subpartes é a latência total de interação. Cada subparte de uma interação contribui com um determinado tempo para a latência total da interação. Por isso, é importante saber como otimizar cada parte para que ela seja executada pelo menor tempo possível.

Identificar e reduzir a latência na entrada

Quando um usuário interage com uma página, a primeira parte dessa interação é o atraso de entrada. Dependendo de outras atividades na página, os atrasos de entrada podem ser consideráveis. Isso pode ser causado por atividades na linha de execução principal (talvez devido ao carregamento, análise e compilação de scripts), processamento de busca, funções de timer ou até mesmo por outras interações que ocorrem em rápida sucessão e se sobrepõem.

Seja qual for a origem do atraso de entrada de uma interação, é importante reduzir esse atraso ao mínimo para que as interações possam começar a executar callbacks de eventos o mais rápido possível.

A relação entre a avaliação de script e tarefas longas durante a inicialização

Um aspecto essencial da interatividade no ciclo de vida da página é durante a inicialização. Quando uma página é carregada, ela é renderizada inicialmente. No entanto, é importante lembrar que só porque uma página foi renderizada, não significa que ela terminou de carregar. Dependendo de quantos recursos uma página precisa para se tornar totalmente funcional, é possível que os usuários tentem interagir com ela enquanto ainda está carregando.

Uma coisa que pode aumentar o atraso de entrada de uma interação enquanto uma página é carregada é a avaliação de script. Depois que um arquivo JavaScript é buscado na rede, o navegador ainda precisa fazer o trabalho de analisar um script para verificar se a sintaxe é válida, compilá-lo em bytecode e, finalmente, executá-lo.

Dependendo do tamanho de um script, esse trabalho pode introduzir tarefas longas na linha de execução principal, o que atrasa a resposta do navegador a outras interações do usuário. Para manter a página responsiva à entrada do usuário durante o carregamento, é importante entender o que você pode fazer para reduzir a probabilidade de tarefas longas durante o carregamento da página e manter a página rápida.

Otimizar callbacks de eventos

O atraso de entrada é apenas a primeira parte do que o INP mede. Também é necessário garantir que os callbacks de eventos executados em resposta a uma interação do usuário sejam concluídos o mais rápido possível.

Ceda à linha de execução principal com frequência

A melhor dica geral para otimizar callbacks de eventos é fazer o mínimo de trabalho possível neles. No entanto, sua lógica de interação pode ser complexa, e talvez seja possível reduzir apenas marginalmente o trabalho que eles fazem.

Se for esse o caso do seu site, a próxima etapa é dividir o trabalho em callbacks de eventos em tarefas separadas. Isso evita que o trabalho coletivo se torne uma tarefa longa que bloqueia a linha de execução principal, permitindo que outras interações que ficariam esperando na linha de execução principal sejam executadas antes.

setTimeout é uma maneira de dividir tarefas, porque o callback transmitido a ele é executado em uma nova tarefa. Você pode usar setTimeout por conta própria ou abstrair o uso em uma função separada para uma geração mais ergonômica.

Fazer isso de forma indiscriminada é melhor do que não fazer nada. No entanto, há uma maneira mais sutil de ceder à linha de execução principal, que envolve apenas ceder imediatamente após um callback de evento que atualiza a interface do usuário para que a lógica de renderização possa ser executada mais cedo.

Ceda para permitir que o trabalho de renderização ocorra antes

Uma técnica de geração mais avançada envolve estruturar o código nos callbacks de eventos para limitar o que é executado apenas à lógica necessária para aplicar atualizações visuais no próximo frame. Todo o resto pode ser adiado para uma tarefa posterior. Isso não apenas mantém os callbacks leves e ágeis, mas também melhora o tempo de renderização das interações, não permitindo que as atualizações visuais bloqueiem o código de callback de eventos.

Por exemplo, imagine um editor de rich text que formata o texto enquanto você digita, mas também atualiza outros aspectos da interface em resposta ao que você escreveu (como contagem de palavras, destaque de erros de ortografia e outros feedbacks visuais importantes). Além disso, o aplicativo também pode precisar salvar o que você escreveu para que, se você sair e voltar, não perca nada.

Neste exemplo, as quatro ações a seguir precisam acontecer em resposta aos caracteres digitados pelo usuário. No entanto, apenas o primeiro item precisa ser feito antes da apresentação do próximo frame.

  1. Atualize a caixa de texto com o que o usuário digitou e aplique a formatação necessária.
  2. Atualize a parte da interface que mostra a contagem de palavras atual.
  3. Executar lógica para verificar erros de ortografia.
  4. Salve as mudanças mais recentes (localmente ou em um banco de dados remoto).

O código para fazer isso pode ser parecido com o seguinte:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

A visualização a seguir mostra como adiar atualizações não críticas até depois do próximo frame pode reduzir a duração do processamento e, portanto, a latência geral da interação.