Em direção a uma melhor métrica de capacidade de resposta

Saiba o que pensamos sobre como medir a capacidade de resposta e envie seu feedback.

Annie Sullivan
Annie Sullivan
Hongbo Song
Hongbo Song
Nicolás Peña Moreno
Nicolás Peña Moreno

Na equipe de Métricas de velocidade do Chrome, estamos trabalhando para aprofundar nosso conhecimento sobre a rapidez com que as páginas da Web respondem à entrada do usuário. Gostaríamos de compartilhar algumas ideias para melhorar as métricas de capacidade de resposta e ouvir seu feedback.

Esta postagem abordará dois tópicos principais:

  1. Revise nossa métrica de capacidade de resposta atual, latência na primeira entrada (FID, na sigla em inglês), e explique por que escolhemos a FID em vez de algumas alternativas.
  2. Apresente algumas melhorias que estamos considerando para capturar melhor a latência de ponta a ponta dos eventos individuais. Essas melhorias também visam capturar uma visão mais abrangente da capacidade de resposta geral de uma página ao longo do ciclo de vida dela.

O que é a latência na primeira entrada?

A métrica Latência na primeira entrada (FID, na sigla em inglês) mede quanto tempo leva para o navegador começar a processar a primeira interação do usuário em uma página. Em particular, ela mede a diferença entre o momento em que o usuário interage com o dispositivo e o momento em que o navegador pode começar a processar manipuladores de eventos. A FID é medida apenas por toques e pressionamentos de teclas, o que significa que ela considera apenas a primeira ocorrência dos seguintes eventos:

  • click
  • keydown
  • mousedown
  • pointerdown (somente se for seguido por pointerup)

O diagrama a seguir ilustra a FID:

A latência na primeira entrada mede
desde quando a entrada ocorre até quando ela pode ser processada

A FID não inclui o tempo gasto na execução desses manipuladores de eventos nem qualquer trabalho feito pelo navegador depois para atualizar a tela. Mede por quanto tempo a linha de execução principal ficou ocupada antes de processar uma entrada. Esse tempo de bloqueio geralmente é causado por longas tarefas de JavaScript, já que elas não podem ser interrompidas a qualquer momento. Portanto, a tarefa atual precisa ser concluída antes que o navegador comece a processar a entrada.

Por que escolhemos a FID?

Acreditamos que é importante avaliar a experiência real do usuário para garantir que as melhorias na métrica resultem em benefícios reais para o usuário. Escolhemos medir a FID porque ela representa a parte da experiência do usuário quando ele decide interagir com um site que acabou de ser carregado. A FID registra o tempo que o usuário precisa aguardar até receber uma resposta da interação com um site. Em outras palavras, a FID é um limite inferior do tempo que um usuário aguarda após a interação.

Outras métricas, como Tempo total de bloqueio (TBT, na sigla em inglês) e Tempo para interação da página (TTI, na sigla em inglês) são baseadas em tarefas longas e, como o FID, também medem o tempo de bloqueio da linha de execução principal durante o carregamento. Como essas métricas podem ser medidas no campo e no laboratório, muitos desenvolvedores perguntaram por que não preferimos uma delas em vez da FID.

Há várias razões para isso acontecer. Talvez o motivo mais importante seja que essas métricas não medem diretamente a experiência do usuário. Todas essas métricas medem quanto JavaScript é executado na página. Embora o JavaScript de longa duração tende a causar problemas aos sites, essas tarefas não afetam necessariamente a experiência do usuário se ele não estiver interagindo com a página quando ocorrerem. Uma página pode ter uma ótima pontuação de TBT e TTI, mas pode parecer lenta ou ter uma pontuação ruim enquanto agiliza os usuários. De acordo com nossa experiência, essas medições indiretas resultam em métricas que funcionam muito bem para alguns sites, mas não para a maioria deles. Em resumo, o fato de que tarefas longas e TTI não são centradas no usuário torna esses candidatos mais fracos.

Embora a medição de laboratórios seja certamente importante e uma ferramenta de valor inestimável para o diagnóstico, o que realmente importa é a experiência dos usuários com os sites. Com uma métrica centrada no usuário que reflete as condições reais do usuário, você garante a captura de algo significativo sobre a experiência. Decidimos começar com uma pequena parte dessa experiência, mesmo que saibamos que ela não representa a experiência completa. É por isso que estamos trabalhando para capturar uma parte maior do tempo que o usuário espera até que as entradas sejam processadas.

Observação sobre a medição de TTI no campo

Medir o TTI em usuários reais no campo é problemático porque ocorre muito tarde no carregamento da página. Uma janela silenciosa de rede de cinco segundos é necessária antes que o TTI possa ser calculado. No laboratório, é possível descarregar a página sempre que você tiver todos os dados necessários, mas esse não é o caso com o monitoramento de usuários reais em campo. O usuário pode sair da página ou interagir com ela a qualquer momento. Especificamente, os usuários podem optar por sair de páginas que levam muito tempo para carregar, e um TTI preciso não será registrado nesses casos. Quando avaliamos o TTI para usuários reais no Chrome, descobrimos que apenas cerca de metade dos carregamentos de página atingiram o TTI.

Que melhorias estamos considerando?

Gostaríamos de desenvolver uma nova métrica que amplie as medidas de FID atuais, mas ainda mantenha a forte conexão com a experiência do usuário.

Queremos que a nova métrica:

  1. Considere a capacidade de resposta de todas as entradas do usuário (não apenas a primeira)
  2. Capture toda a duração de cada evento, não apenas o atraso.
  3. Agrupe eventos que ocorrem como parte da mesma interação lógica do usuário e defina a latência dessa interação como a duração máxima de todos os eventos.
  4. Crie uma pontuação agregada para todas as interações que ocorrem em uma página, ao longo do ciclo de vida completo.

Para ter sucesso, precisamos dizer, com alto nível de confiança, que, se um site apresentar baixa pontuação nessa nova métrica, ele não estará respondendo rapidamente às interações do usuário.

Capturar toda a duração do evento

A primeira melhoria óbvia é tentar capturar uma latência de ponta a ponta mais ampla de um evento. Como mencionado acima, a FID captura apenas a parte de atraso do evento de entrada. Ela não considera o tempo que o navegador leva para processar os manipuladores de eventos.

Há vários estágios no ciclo de vida de um evento, conforme ilustrado neste diagrama:

Cinco etapas no
ciclo de vida de um evento

Estas são as etapas que o Chrome executa para processar uma entrada:

  1. A entrada do usuário ocorre. O horário em que isso ocorre é o timeStamp do evento.
  2. O navegador realiza testes de hit para decidir a qual frame HTML (frame principal ou algum iframe) um evento pertence. Em seguida, o navegador envia o evento para o processo do renderizador apropriado responsável pelo frame HTML.
  3. O renderizador recebe o evento e o coloca na fila para que ele possa processar quando estiver disponível.
  4. O renderizador processa o evento executando seus manipuladores. Esses gerenciadores podem enfileirar outros trabalhos assíncronos, como setTimeout e buscas, que fazem parte do processamento de entrada. Mas, neste ponto, o trabalho síncrono está concluído.
  5. Um frame é pintado na tela que reflete o resultado da execução de manipuladores de eventos. Observe que as tarefas assíncronas enfileiradas pelos manipuladores de eventos ainda podem estar incompletas.

O tempo entre as etapas (1) e (3) acima é o atraso de um evento, que é medido pela FID.

O tempo entre as etapas (1) e (5) acima é a duração de um evento. Isso é o que nossa nova métrica avaliará.

A duração do evento inclui o atraso, mas também o trabalho que ocorre nos manipuladores de eventos e o trabalho que o navegador precisa realizar para pintar o próximo frame após a execução desses manipuladores. No momento, a duração de um evento está disponível na API Event Timing pelo atributo duration da entrada.

Observação sobre tarefas assíncronas

Idealmente, adoraríamos capturar também o trabalho assíncrono acionado pelo evento. Mas o problema é que a definição de trabalho assíncrono acionado pelo evento é extremamente difícil de acertar. Por exemplo, um desenvolvedor pode optar por iniciar uma animação em manipuladores de eventos e usar um setTimeout para iniciá-la. Se capturamos todas as tarefas publicadas nos gerenciadores, a animação atrasaria o tempo de conclusão enquanto a animação fosse executada. Acreditamos que vale a pena investigar opções sobre como usar a heurística para capturar trabalhos que são assíncronos e que precisam ser concluídos o mais rápido possível. No entanto, queremos ter muito cuidado ao fazer isso, porque não queremos penalizar o trabalho que precisa levar muito tempo para ser concluído. Assim, nosso esforço inicial considerará a etapa 5 como o ponto final: considerará apenas o trabalho síncrono e o tempo necessário para pintar após a conclusão desse trabalho. Ou seja, não vamos aplicar heurísticas para adivinhar o trabalho que seria iniciado de modo assíncrono na etapa 4 em nosso esforço inicial.

É importante notar que, em muitos casos, o trabalho deve ser executado de forma síncrona. Na verdade, isso pode ser inevitável porque às vezes os eventos são enviados um após o outro, e os manipuladores de eventos precisam ser executados em ordem. Dito isso, ainda vamos perder trabalhos importantes, como eventos que acionam a busca ou que dependem de um trabalho importante a ser feito no próximo callback requestAnimationFrame, por exemplo.

Agrupar eventos em interações

Estender a medição da métrica de delay para duration é uma boa primeira etapa, mas ainda deixa uma lacuna crítica na métrica: ela se concentra em eventos individuais e não na experiência do usuário de interagir com a página.

Muitos eventos diferentes podem ser acionados como resultado de uma única interação do usuário, e a medição separada de cada um deles não cria uma imagem clara do que o usuário experimenta. Queremos garantir que a métrica capture a quantidade total de tempo que um usuário tem que esperar por uma resposta ao tocar, pressionar teclas, rolar e arrastar com a maior precisão possível. Estamos introduzindo o conceito de interações para medir a latência de cada uma.

Tipos de interação

A tabela a seguir lista as quatro interações que queremos definir com os eventos DOM a que estão associados. Isso não é igual ao conjunto de todos os eventos que são enviados quando essa interação do usuário ocorre. Por exemplo, quando um usuário rola a tela, um evento de rolagem é enviado, mas acontece depois que a tela é atualizada para refletir a rolagem. Portanto, não o consideramos parte da latência da interação.

Interação Início / fim Eventos no computador Eventos em dispositivos móveis
Teclado Tecla pressionada keydown keydown
keypress keypress
Chave liberada keyup keyup
Tocar ou arrastar Toque em "Iniciar" ou "Arrastar" para iniciar pointerdown pointerdown
mousedown touchstart
Fim do toque ou arrastar pointerup pointerup
mouseup touchend
click mousedown
mouseup
click
Rolagem N/A
Eventos DOM para cada tipo de interação.

No momento, as três primeiras interações listadas acima (teclado, tocar e arrastar) são cobertas pela FID. Para nossa nova métrica de capacidade de resposta, também queremos incluir a rolagem, já que ela é extremamente comum na Web e é um aspecto crítico de como uma página é responsiva para os usuários.

Uma observação sobre início e fim

Cada uma dessas interações tem duas partes: quando o usuário pressiona o mouse, dedo ou tecla para baixo e quando o usuário o levanta. Precisamos garantir que nossa métrica não conte o tempo que o usuário passa segurando o dedo entre essas duas ações como parte da latência da página.

Teclado

Uma interação com o teclado tem duas partes: quando o usuário pressiona a tecla e quando a solta. Há três eventos associados a essa interação do usuário: keydown, keyup e keypress. O diagrama a seguir ilustra os atrasos e durações de keydown e keyup de uma interação de teclado:

Interação do teclado
com durações de eventos independentes

No diagrama acima, as durações são separadas porque o frame das atualizações de keydown é apresentado antes de a keyup ocorrer, mas isso não precisa ser sempre o caso. Além disso, um frame pode ser apresentado no meio de uma tarefa no processo do renderizador, já que as últimas etapas necessárias para produzi-lo são feitas fora desse processo.

A keydown e a keypress ocorrem quando o usuário pressiona a tecla, enquanto a keyup ocorre quando o usuário solta a chave. Geralmente, a atualização do conteúdo principal ocorre quando a tecla é pressionada: o texto aparece na tela ou o efeito modificador é aplicado. Dito isso, queremos capturar os casos mais raros em que keyup também apresentaria atualizações de interface interessantes. Por isso, queremos analisar o tempo geral gasto.

Para capturar o tempo total da interação com o teclado, podemos calcular a duração máxima da duração dos eventos keydown e keyup.

Uma observação sobre pressionamentos de tecla repetidos

Há um caso extremo aqui que vale a pena mencionar: há casos em que o usuário pressiona uma tecla e demora um pouco para soltá-la. Nesse caso, a sequência de eventos enviados pode variar. Nesses casos, consideramos que há uma interação por keydown, que pode ou não ter um keyup correspondente.

Toque em

Outra interação importante é quando o usuário toca ou clica em um site. De forma semelhante a keypress, alguns eventos são disparados quando o usuário pressiona e outros à medida que ele solta, conforme mostrado no diagrama acima. Os eventos associados a um toque são um pouco diferentes no computador e no dispositivo móvel.

Para um toque ou clique, a versão geralmente é a que aciona a maioria das reações, mas, como acontece com as interações do teclado, queremos capturar a interação completa. Nesse caso, é mais importante fazer isso, porque ter algumas atualizações de interface ao pressionar um toque não é tão incomum.

Gostaríamos de incluir as durações de todos esses eventos, mas como muitos deles se sobrepõem completamente, precisamos medir apenas pointerdown, pointerup e click para abranger a interação completa.

Podemos restringir mais apenas a pointerdown e pointerup?

Uma ideia inicial seria usar os eventos pointerdown e pointerup e presumir que eles abrangem todas as durações em que estamos interessados. Infelizmente, esse não é o caso, como mostra este caso extremo. Tente abrir o site em um dispositivo móvel ou com emulação de dispositivos móveis e toque onde diz "Clique em mim". Este site aciona o atraso de toque no navegador. pointerdown, pointerup e touchend são enviados rapidamente, enquanto mousedown, mouseup e click aguardam o atraso antes de serem enviados. Isso significa que, se analisarmos apenas pointerdown e pointerup, perderíamos a duração dos eventos sintéticos, o que é grande devido ao atraso de toque do navegador e precisa ser incluído. Portanto, precisamos medir pointerdown, pointerup e click para abranger a interação completa.

Arrasto

Decidimos incluir o recurso de arrastar também, já que ele tem eventos associados semelhantes e geralmente causa atualizações importantes na interface dos sites. No entanto, para nossa métrica, pretendemos considerar apenas o início e o fim da ação, ou seja, as partes inicial e final. Isso facilita o raciocínio e torna as latências comparáveis às outras interações consideradas. Isso é consistente com nossa decisão de excluir eventos contínuos, como mouseover.

Também não estamos considerando as ações de arrastar implementadas pela API Drag and Drop, porque elas só funcionam em computadores.

Rolagem

Uma das formas mais comuns de interagir com um site é por meio da rolagem. Para nossa nova métrica, queremos medir a latência da interação de rolagem inicial do usuário. Em particular, nos preocupamos com a reação inicial do navegador ao fato de o usuário ter solicitado uma rolagem. Não vamos colocar toda a experiência de rolagem. Ou seja, a rolagem produz muitos frames, e vamos focar nossa atenção no frame inicial produzido como uma reação à rolagem.

Por que só o primeiro? Por um lado, os frames subsequentes podem ser capturados por uma proposta de suavidade separada. Ou seja, depois que o primeiro resultado da rolagem é mostrado ao usuário, o restante precisa ser medido em termos de fluidez da experiência de rolagem. Portanto, acreditamos que o esforço de suavidade poderia capturar melhor isso. Assim como acontece com a FID, optamos por experiências do usuário discretas: experiências do usuário que têm pontos claros no tempo associados a elas e para os quais podemos calcular facilmente a latência. A rolagem como um todo é uma experiência contínua. Portanto, não pretendemos medir tudo com essa métrica.

Por que medir pergaminhos? O desempenho de rolagem que observamos no Chrome mostra que a rolagem geralmente é muito rápida. Dito isso, ainda queremos incluir as latências iniciais de rolagem na nova métrica por vários motivos. Primeiro, a rolagem é rápida apenas porque foi muito otimizada, porque é muito importante. No entanto, ainda há maneiras de um site ignorar alguns dos ganhos de desempenho que o navegador oferece. A mais comum no Chrome é forçar a rolagem na linha de execução principal. Portanto, nossa métrica precisa informar quando isso acontece e causa um desempenho ruim de rolagem para os usuários. Em segundo lugar, a rolagem é muito importante para ser ignorada. Preocupamos que, se excluirmos a rolagem, teremos um grande ponto cego, e o desempenho da rolagem poderá diminuir com o tempo sem que os desenvolvedores da Web percebam corretamente.

Há vários eventos que são enviados quando um usuário rola a tela, como touchstart, touchmove e scroll. Exceto pelo evento de rolagem, ele depende em grande parte do dispositivo usado para rolagem: os eventos de toque são enviados ao rolar com o dedo em dispositivos móveis, enquanto os eventos de roda ocorrem ao rolar com a roda do mouse. Os eventos de rolagem são disparados depois que a rolagem inicial é concluída. E, em geral, nenhum evento DOM bloqueia a rolagem, a menos que o site use listeners de eventos não passivos. Então, pensamos na rolagem como totalmente separada dos eventos DOM. O que queremos medir é o tempo entre o momento em que o usuário se move o suficiente para produzir um gesto de rolagem até o primeiro frame que mostra que a rolagem aconteceu.

Como definir a latência de uma interação?

Como observamos acima, as interações que têm componentes "para baixo" e "para cima" precisam ser consideradas separadas para evitar a atribuição do tempo que o usuário passou segurando o dedo.

Para esses tipos de interação, queremos que a latência envolva a duração de todos os eventos associados. Como as durações de eventos para cada parte "para baixo" e "para cima" da interação podem se sobrepor, a definição mais simples de latência de interação que alcança isso é a duração máxima de qualquer evento associado a ela. Voltando ao diagrama do teclado mostrado anteriormente, essa seria a duração de keydown, já que é maior que keyup:

Interação do teclado
com duração máxima destacada

As durações keydown e keyup também podem se sobrepor. Isso pode acontecer, por exemplo, quando o frame apresentado para os dois eventos é o mesmo, como no diagrama a seguir:

Interação pelo teclado,
em que o pressionamento e a liberação ocorrem no mesmo frame

Há prós e contras nessa abordagem de usar o máximo, e queremos ouvir seu feedback:

  • Vantagem: está alinhada com a maneira como pretendemos medir a rolagem, porque mede apenas um único valor de duração.
  • Vantagens: o objetivo é reduzir o ruído em casos como interações com o teclado, em que o keyup geralmente não faz nada e em que o usuário pode pressionar e soltar uma tecla de forma rápida ou lenta.
  • Desvantagem: não captura o tempo total de espera do usuário. Por exemplo, ela vai capturar o início ou o fim de uma ação de arrastar, mas não ambos.

Para rolagem (que tem apenas um evento associado), queremos definir a latência como o tempo que o navegador leva para produzir o primeiro frame como resultado da rolagem. Ou seja, a latência é o delta entre o evento timeStamp do primeiro evento DOM (como touchmove, se estiver usando um dedo) grande o suficiente para acionar uma rolagem e a primeira exibição, que reflete a rolagem que está ocorrendo.

Agregar todas as interações por página

Após definir a latência de uma interação, precisamos calcular um valor agregado para o carregamento de uma página, que pode ter muitas interações do usuário. Ter um valor agregado nos permite:

  • Forme correlações com métricas de negócios.
  • Avalie as correlações com outras métricas de desempenho. Idealmente, nossa nova métrica será suficientemente independente para agregar valor às métricas existentes.
  • Exponha facilmente os valores nas ferramentas de maneiras fáceis de digerir.

Para fazer essa agregação, precisamos resolver duas perguntas:

  1. Que números tentamos agregar?
  2. Como agregamos esses números?

Estamos explorando e avaliando várias opções. Sua opinião sobre essa agregação é muito bem-vinda.

Uma opção é definir um orçamento para a latência de uma interação, que pode depender do tipo (rolar, usar teclado, tocar ou arrastar). Por exemplo, se o orçamento para toques for de 100 ms e a latência de um toque for de 150 ms, o valor além do orçamento para essa interação será de 50 ms. Então, podemos calcular a quantidade máxima de latência que ultrapassa o orçamento para qualquer interação do usuário na página.

Outra opção é calcular a latência média ou mediana das interações ao longo da vida útil da página. Portanto, se tivéssemos latências de 80 ms, 90 ms e 100 ms, a latência média da página seria de 90 ms. Também poderíamos considerar a média ou mediana "acima do orçamento" para considerar as diferentes expectativas, dependendo do tipo de interação.

Como isso fica nas APIs de desempenho na Web?

O que está faltando na "Programação do evento"?

Infelizmente, nem todas as ideias apresentadas nesta postagem podem ser capturadas usando a API Event Timing. Em especial, não há uma maneira simples de saber os eventos associados a determinada interação do usuário com a API. Para fazer isso, propomos adicionar um interactionID à API.

Outra desvantagem da API Event Timing é que não há como medir a interação de rolagem. Portanto, estamos trabalhando para ativar essas medições (com a Event Timing ou outra API).

O que você pode tentar agora?

No momento, ainda é possível calcular a latência máxima para toques/arrastar e interações com teclado. O snippet de código a seguir produziria essas duas métricas.

let maxTapOrDragDuration = 0;
let maxKeyboardDuration = 0;
const observer = new PerformanceObserver(list => {
  list.getEntries().forEach(entry => {
    switch(entry.name) {
      case "keydown":
      case "keyup":
        maxKeyboardDuration = Math.max(maxKeyboardDuration,
            entry.duration);
        break;
      case "pointerdown":
      case "pointerup":
      case "click":
        maxTapOrDragDuration = Math.max(maxTapOrDragDuration,
            entry.duration);
        break;
    }
  });
});
observer.observe({type: "event", durationThreshold: 16, buffered: true});
// We can report maxTapDragDuration and maxKeyboardDuration when sending
// metrics to analytics.

Feedback

Envie um e-mail para web-vitals-feedback@googlegroups.com e dê sua opinião sobre essas ideias.