Hacia una mejor métrica de capacidad de respuesta

Conoce nuestras ideas sobre cómo medir la capacidad de respuesta y envíanos tus comentarios.

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

En el equipo de métricas de velocidad de Chrome, estamos trabajando para profundizar nuestros conocimientos sobre la rapidez con la que las páginas web responden a las entradas de los usuarios. Nos gustaría compartir algunas ideas para mejorar las métricas de capacidad de respuesta y escuchar tus comentarios.

Esta publicación abarcará dos temas principales:

  1. Revisa nuestra métrica de capacidad de respuesta actual, Retraso de primera entrada (FID), y explica por qué elegimos FID en lugar de algunas de las alternativas.
  2. Presenta algunas mejoras que consideramos que deberían capturar mejor la latencia de extremo a extremo de los eventos individuales. El objetivo de estas mejoras también es capturar un panorama más integral de la capacidad de respuesta general de una página a lo largo de su vida útil.

¿Qué es el retraso de primera entrada?

La métrica Retraso de primera entrada (FID) mide cuánto tiempo tarda el navegador en comenzar a procesar la primera interacción del usuario en una página. En particular, mide la diferencia entre el momento en el que el usuario interactúa con el dispositivo y el momento en el que el navegador puede comenzar a procesar los controladores de eventos. El FID solo se mide cuando se presiona y se presiona una tecla, lo que significa que solo considera la primera instancia de los siguientes eventos:

  • click
  • keydown
  • mousedown
  • pointerdown (solo si va seguido de pointerup)

En el siguiente diagrama, se ilustra el FID:

El retraso de primera entrada mide desde que se produce la entrada hasta que se puede controlar

El FID no incluye el tiempo dedicado a ejecutar esos controladores de eventos ni el trabajo que realiza el navegador después para actualizar la pantalla. Mide la cantidad de tiempo que el subproceso principal estuvo ocupado antes de tener la oportunidad de controlar una entrada. Por lo general, este tiempo de bloqueo se debe a tareas largas de JavaScript, ya que no se pueden detener en cualquier momento. Por ello, la tarea actual debe completarse antes de que el navegador comience a procesar la entrada.

¿Por qué elegimos FID?

Creemos que es importante medir la experiencia real del usuario para garantizar que las mejoras en la métrica generen beneficios reales para el usuario. Elegimos medir el FID porque representa la parte de la experiencia del usuario cuando este decide interactuar con un sitio que se acaba de cargar. El FID captura parte del tiempo que el usuario debe esperar para ver una respuesta de su interacción con un sitio. En otras palabras, el FID es un límite inferior para la cantidad de tiempo que un usuario espera después de interactuar.

Otras métricas, como el Tiempo de bloqueo total (TBT) y el Tiempo de carga (TTI), se basan en tareas largas y, al igual que el FID, también miden el tiempo de bloqueo del subproceso principal durante la carga. Dado que estas métricas se pueden medir tanto en el campo como en el lab, muchos desarrolladores preguntaron por qué no preferimos una de estas en lugar de FID.

Existen varios motivos para esto. Quizás el motivo más importante es que estas métricas no miden la experiencia del usuario directamente. Todas estas métricas miden cuánto se ejecuta JavaScript en la página. Si bien la ejecución prolongada de JavaScript suele causar problemas en los sitios, estas tareas no necesariamente afectan la experiencia del usuario si este no interactúa con la página cuando se producen. Una página puede tener una puntuación alta en TBT y TTI, pero puede parecer lenta o puede tener una puntuación baja a la vez que se siente rápida para los usuarios. Según nuestra experiencia, estas mediciones indirectas generan métricas que funcionan muy bien para algunos sitios, pero no para la mayoría. En resumen, el hecho de que las tareas largas y el TTI no se centren en el usuario convierte a estos candidatos menos seguros.

Si bien la medición de labs es sin duda importante y una herramienta invaluable para el diagnóstico, lo que realmente importa es la experiencia de los usuarios en los sitios. Con una métrica centrada en el usuario que refleja las condiciones del usuario real, tienes la garantía de capturar algo significativo sobre la experiencia. Decidimos comenzar con una pequeña parte de esa experiencia, aunque sabemos que no es representativa de la experiencia completa. Por eso, estamos trabajando para capturar una porción más grande del tiempo que un usuario espera a que se manejen sus entradas.

Nota sobre la medición de TTI en el campo

Medir el TTI de los usuarios reales en el campo es problemático porque se produce muy tarde en la carga de la página. Se requiere un período de inactividad de 5 segundos en la red antes de que se pueda calcular el TTI. En el lab, puedes descargar la página cuando tengas todos los datos que necesitas, pero ese no es el caso con la supervisión de usuarios reales en el campo. Los usuarios pueden abandonar la página o interactuar con ella en cualquier momento. En particular, los usuarios pueden optar por abandonar las páginas que tardan mucho tiempo en cargarse y no se registrará una TTI precisa en esos casos. Cuando medimos el TTI de los usuarios reales en Chrome, descubrimos que solo la mitad de las cargas de la página alcanzaron el TTI.

¿Qué mejoras estamos considerando?

Nos gustaría desarrollar una nueva métrica que extienda lo que FID mide actualmente y que aún conserve su buena conexión con la experiencia del usuario.

Queremos que la métrica nueva:

  1. Considera la capacidad de respuesta de todas las entradas del usuario (no solo la primera).
  2. Captura la duración completa de cada evento (no solo la demora).
  3. Agrupa los eventos que ocurren como parte de la misma interacción lógica del usuario y define la latencia de esa interacción como la duración máxima de todos sus eventos.
  4. Crea una puntuación agregada para todas las interacciones que ocurren en una página, durante todo su ciclo de vida.

Para tener éxito, deberíamos poder decir con gran confianza que si un sitio obtiene una puntuación baja en esta métrica nueva, no responde rápidamente a las interacciones del usuario.

Captura la duración completa del evento

La primera mejora evidente es tratar de capturar una latencia más amplia de extremo a extremo de un evento. Como se mencionó anteriormente, el FID solo captura la parte de retraso del evento de entrada. No tiene en cuenta el tiempo que le toma al navegador procesar los controladores de eventos.

Hay varias etapas en el ciclo de vida de un evento, como se ilustra en este diagrama:

Cinco pasos en el
ciclo de vida de un evento

A continuación, se indican los pasos que sigue Chrome para procesar una entrada:

  1. Se produce la entrada del usuario. La hora en la que esto ocurre es la timeStamp del evento.
  2. El navegador realiza pruebas de posicionamiento para decidir a qué marco HTML (marco principal o algún iframe) pertenece un evento. Luego, el navegador envía el evento al proceso del procesador adecuado a cargo de ese marco HTML.
  3. El procesador recibe el evento y lo pone en cola para que pueda procesarlo cuando esté disponible.
  4. El procesador procesa el evento ejecutando sus controladores. Estos controladores pueden poner en cola trabajo asíncrono adicional, como setTimeout y recuperaciones, que son parte del control de entradas. Sin embargo, en este punto, el trabajo síncrono está completo.
  5. Se pinta un marco en la pantalla que refleja el resultado de la ejecución de controladores de eventos. Ten en cuenta que las tareas asíncronas en cola por los controladores de eventos pueden quedar sin terminar.

El tiempo entre los pasos (1) y (3) anteriores es el retraso de un evento, que es lo que mide FID.

El tiempo entre los pasos (1) y (5) anteriores es la duración de un evento. Esto es lo que medirá nuestra nueva métrica.

La duración del evento incluye el retraso, pero también incluye el trabajo que ocurre en los controladores de eventos y el trabajo que debe hacer el navegador para pintar el siguiente fotograma después de que se hayan ejecutado esos controladores. Actualmente, la duración de un evento está disponible en la API de Event Timing mediante el atributo duration de la entrada.

Nota sobre las tareas asíncronas

Idealmente, también nos encantaría capturar el trabajo asíncrono activado por el evento. Sin embargo, el problema es que la definición de trabajo asíncrono activado por el evento es muy difícil de entender. A modo de ejemplo, un desarrollador puede optar por iniciar alguna animación en los controladores de eventos y usar un setTimeout para comenzar esa animación. Si capturamos todas las tareas publicadas en los controladores, la animación retrasaría el tiempo de finalización mientras se ejecute la animación. Creemos que vale la pena investigar las opciones sobre cómo usar la heurística para capturar trabajo asíncrono que debe completarse lo antes posible. Sin embargo, debemos tener mucho cuidado al hacerlo, ya que no queremos penalizar al trabajo que demore mucho tiempo en terminarse. Por lo tanto, nuestro esfuerzo inicial considerará el paso 5 como el destino: solo considerará el trabajo síncrono y la cantidad de tiempo que se tarda en pintar una vez que se completa ese trabajo. Es decir, no aplicaremos heurísticas para adivinar el trabajo que se iniciaría de forma asíncrona en el paso 4 de nuestro esfuerzo inicial.

Vale la pena señalar que, en muchos casos, el trabajo debe ejecutarse de forma síncrona. De hecho, esto puede ser inevitable porque los eventos a veces se envían uno tras otro y los controladores de eventos deben ejecutarse en orden. Dicho esto, aún perderemos trabajos importantes, como los eventos que activan la recuperación o que dependen de un trabajo importante que se realice en la próxima devolución de llamada requestAnimationFrame, por ejemplo.

Agrupa eventos en interacciones

Extender la medición de la métrica de delay a duration es un buen primer paso, pero deja una brecha crítica en la métrica: se centra en eventos individuales y no en la experiencia del usuario de la interacción con la página.

Muchos eventos diferentes pueden activarse como resultado de una sola interacción del usuario, y medir cada uno por separado no crea un panorama claro de lo que experimenta el usuario. Queremos asegurarnos de que nuestra métrica capture la cantidad total de tiempo que un usuario tiene que esperar una respuesta cuando presiona, presiona las teclas, se desplaza y arrastra con la mayor precisión posible. Por lo tanto, presentamos el concepto de interacciones para medir la latencia de cada una.

Tipos de interacción

En la siguiente tabla, se enumeran las cuatro interacciones que queremos definir junto con los eventos del DOM con los que están asociados. Ten en cuenta que no es lo mismo que el conjunto de todos los eventos que se envían cuando ocurre esa interacción del usuario. Por ejemplo, cuando un usuario se desplaza, se envía un evento de desplazamiento, pero sucede después de que se actualiza la pantalla para reflejar el desplazamiento, por lo que no se considera parte de la latencia de la interacción.

Interacción Inicio / finalización Eventos en computadoras de escritorio Eventos para dispositivos móviles
Teclado Se presionó la tecla keydown keydown
keypress keypress
Clave liberada keyup keyup
Presionar o arrastrar Presiona Iniciar o arrastrar Inicio pointerdown pointerdown
mousedown touchstart
Presionar hacia arriba o arrastrar el final pointerup pointerup
mouseup touchend
click mousedown
mouseup
click
Desplázate N/A
Eventos del DOM para cada tipo de interacción.

Las primeras tres interacciones enumeradas anteriormente (teclado, presionar y arrastrar) están cubiertas por el FID actualmente. Para nuestra nueva métrica de capacidad de respuesta, también queremos incluir el desplazamiento, ya que el desplazamiento es muy común en la Web y es un aspecto crítico de qué tan responsiva es la página para los usuarios.

Nota al comienzo y al final

Ten en cuenta que cada una de estas interacciones tiene dos partes: cuando el usuario presiona el mouse, el dedo o la tecla hacia abajo, y cuando lo levanta. Debemos asegurarnos de que nuestra métrica no registre el tiempo que el usuario mantiene presionado el dedo entre estas dos acciones como parte de la latencia de la página.

Teclado

Una interacción con el teclado tiene dos partes: cuando el usuario presiona la tecla y cuando la suelta. Hay tres eventos asociados con esta interacción del usuario: keydown, keyup y keypress. En el siguiente diagrama, se ilustran los retrasos y la duración de keydown y keyup de una interacción de teclado:

Interacción de teclado
con duraciones inconexas de eventos

En el diagrama anterior, las duraciones son inconexas porque el fotograma de las actualizaciones de keydown se presenta antes de que se produzca keyup, pero no es necesario que sea siempre el caso. Además, ten en cuenta que se puede presentar un fotograma en medio de una tarea en el proceso del procesador, ya que los últimos pasos necesarios para producir el fotograma se realizan fuera del proceso del renderizador.

keydown y keypress se producen cuando el usuario presiona la tecla, mientras que keyup se produce cuando el usuario suelta la tecla. Por lo general, la actualización del contenido principal ocurre cuando se presiona la tecla: aparece texto en la pantalla o se aplica el efecto modificador. Dicho esto, queremos capturar los casos más infrecuentes en los que keyup también presente actualizaciones de IU interesantes, por lo que queremos observar el tiempo total que se tomó.

Para capturar el tiempo total que tomó la interacción del teclado, podemos calcular la duración máxima de los eventos keydown y keyup.

Nota sobre las pulsaciones de teclas repetidas

Existe un caso límite que vale la pena mencionar: puede haber casos en los que el usuario presione una tecla y tarde un poco en soltarla. En este caso, la secuencia de eventos enviados puede variar. En estos casos, consideramos que hay una interacción por keydown, que puede tener o no un keyup correspondiente.

Toque

Otra interacción importante del usuario es cuando el usuario presiona un sitio web o hace clic en él. Al igual que con keypress, algunos eventos se activan cuando el usuario presiona y otros cuando se suelta, como se muestra en el diagrama anterior. Ten en cuenta que los eventos asociados con un toque son un poco diferentes en computadoras de escritorio y dispositivos móviles.

Para un toque o un clic, la versión suele ser la que activa la mayoría de las reacciones, pero, al igual que con las interacciones con el teclado, queremos capturar la interacción completa. En este caso, es más importante hacerlo porque tener algunas actualizaciones de la IU cuando se presiona la pantalla no es poco común.

Nos gustaría incluir la duración de todos estos eventos, pero como muchos de ellos se superponen por completo, debemos medir solo pointerdown, pointerup y click para abarcar la interacción completa.

¿Podemos restringir más a pointerdown y pointerup?

Una idea inicial sería usar los eventos pointerdown y pointerup, y suponer que abarcan todas las duraciones que nos interesan. Lamentablemente, este no es el caso, como se muestra en este caso límite. Intenta abrir el sitio en un dispositivo móvil o con emulación móvil, y presiona donde dice "Haz clic". Este sitio activa la demora en la presión de elementos del navegador. Puede observar que pointerdown, pointerup y touchend se envían rápidamente, mientras que mousedown, mouseup y click esperan el retraso antes del envío. Esto significa que, si solo observamos pointerdown y pointerup, se perdería la duración de los eventos sintéticos, que es grande debido a la demora al presionar el navegador y debería incluirse. Por lo tanto, debemos medir pointerdown, pointerup y click para abarcar la interacción completa.

Arrastrar

También decidimos incluir la función de arrastre porque tiene eventos asociados similares y dado que, por lo general, causa actualizaciones importantes de la IU en los sitios. Sin embargo, para nuestra métrica, solo consideramos el inicio y el final del arrastre, es decir, las partes inicial y final del arrastre. Esto es para que sea más fácil razonar y comparar las latencias con las otras interacciones consideradas. Esto es coherente con nuestra decisión de excluir eventos continuos, como mouseover.

Tampoco consideramos los arrastres implementados a través de la API de arrastrar y soltar, ya que solo funcionan en computadoras de escritorio.

Desplazamiento

Una de las formas más comunes de interactuar con un sitio es mediante el desplazamiento. Para nuestra nueva métrica, nos gustaría medir la latencia para la interacción de desplazamiento inicial del usuario. En particular, nos interesa la reacción inicial del navegador ante el hecho de que el usuario solicitó un desplazamiento. No cubriremos toda la experiencia de desplazamiento. Es decir, el desplazamiento produce muchos fotogramas, y centraremos nuestra atención en el fotograma inicial producido como una reacción al desplazamiento.

¿Por qué solo la primera? Por un lado, los fotogramas siguientes se pueden capturar con una propuesta de suavidad separada. Es decir, una vez que se le muestra al usuario el primer resultado del desplazamiento, el resto debe medirse en términos de qué tan fluida se siente la experiencia de desplazamiento. Por lo tanto, creemos que el esfuerzo de suavidad podría capturar mejor esto. Por lo tanto, al igual que con FID, elegimos apegarnos a experiencias del usuario discretas: experiencias del usuario que tienen puntos de tiempo claros asociados y para las que podemos calcular fácilmente su latencia. El desplazamiento en su conjunto es una experiencia continua, por lo que no pretendemos medirlo todo en esta métrica.

Entonces, ¿por qué medir los desplazamientos? El rendimiento de desplazamiento que reunimos en Chrome muestra que el desplazamiento suele ser muy rápido. Dicho esto, queremos incluir latencias de desplazamiento iniciales en nuestra nueva métrica por varios motivos. En primer lugar, el desplazamiento es rápido solo porque se optimizó mucho y porque es muy importante. Sin embargo, existen maneras en las que un sitio web puede omitir algunas de las ventajas de rendimiento que ofrece el navegador. La más común en Chrome es forzar el desplazamiento en el subproceso principal. Por lo tanto, nuestra métrica debería poder decir cuándo sucede y provoca un rendimiento deficiente del desplazamiento para los usuarios. Segundo, el desplazamiento es demasiado importante como para ignorarlo. Nos preocupa que, si excluimos el desplazamiento, tendremos un gran punto ciego, y el rendimiento del desplazamiento podría disminuir con el tiempo sin que los desarrolladores web lo noten correctamente.

Existen varios eventos que se envían cuando un usuario se desplaza, como touchstart, touchmove y scroll. A excepción del evento de desplazamiento, esto depende en gran medida del dispositivo que se usa para el desplazamiento: los eventos táctiles se envían cuando te desplazas con el dedo en dispositivos móviles, mientras que los eventos de la rueda del mouse se producen cuando te desplazas con la rueda del mouse. Los eventos de desplazamiento se activan una vez que se completa el desplazamiento inicial. Además, en general, ningún evento del DOM bloquea el desplazamiento, a menos que el sitio web utilice objetos de escucha de eventos no pasivos. Por eso, pensamos en el desplazamiento como integrado de los eventos del DOM. Lo que queremos medir es el tiempo que transcurre desde que el usuario se mueve lo suficiente para producir un gesto de desplazamiento hasta que se produce el primer fotograma que muestra ese desplazamiento.

¿Cómo se define la latencia de una interacción?

Como se mencionó anteriormente, las interacciones que tienen componentes "abajo" y "arriba" deben considerarse por separado para evitar que se atribuya el tiempo que el usuario dedicó a mantener presionado el dedo.

Para este tipo de interacciones, queremos que la latencia incluya la duración de todos los eventos asociados con ellas. Dado que las duraciones de los eventos para cada parte de "abajo" y "arriba" de la interacción pueden superponerse, la definición más simple de latencia de interacción que logra esto es la duración máxima de cualquier evento asociado a ella. Si nos referimos al diagrama del teclado anterior, esta sería la duración de keydown, ya que es mayor que keyup:

Interacción con el teclado
con la duración máxima destacada

Las duraciones de keydown y keyup también pueden superponerse. Esto puede ocurrir, por ejemplo, cuando el fotograma presentado para ambos eventos es el mismo, como se muestra en el siguiente diagrama:

Interacción con el teclado, en la que presionar y soltar aparece en el mismo marco

Este enfoque tiene ventajas y desventajas, y nos interesa escuchar tus comentarios:

  • Pro: Se alinea con la forma en que pretendemos medir el desplazamiento, ya que solo mide un valor de duración.
  • Pro: Su objetivo es reducir el ruido en casos como las interacciones con el teclado, en las que keyup no suele hacer nada y en las que el usuario puede presionar y soltar la tecla de forma rápida o lenta.
  • Desventaja: No captura todo el tiempo de espera del usuario. Por ejemplo, capturará el inicio o el final de un arrastre, pero no ambos.

Para el desplazamiento (que solo tiene un evento asociado), nos gustaría definir su latencia como el tiempo que tarda el navegador en producir el primer fotograma como resultado del desplazamiento. Es decir, la latencia es el delta entre el evento timeStamp del primer evento del DOM (como touchmove, si se usa un dedo) que es lo suficientemente grande para activar un desplazamiento y la primera pintura que refleja el desplazamiento que se realiza.

Agregar todas las interacciones por página

Una vez que definamos cuál es la latencia de una interacción, tendremos que calcular un valor agregado para la carga de una página, que puede tener muchas interacciones del usuario. Tener un valor agregado nos permite hacer lo siguiente:

  • Crea correlaciones con métricas empresariales.
  • Evaluar las correlaciones con otras métricas de rendimiento Lo ideal sería que nuestra métrica nueva fuera lo suficientemente independiente como para agregar valor a las métricas existentes.
  • Expone valores con facilidad en las herramientas de formas fáciles de asimilar.

Para realizar esta agregación, tenemos que resolver dos preguntas:

  1. ¿Qué números intentamos sumar?
  2. ¿Cómo sumamos esos números?

Estamos explorando y evaluando varias opciones. Agradecemos tus opiniones sobre esta agregación.

Una opción es definir un presupuesto para la latencia de una interacción, que puede depender del tipo (desplazamiento, teclado, presión o arrastre). Por ejemplo, si el presupuesto de los toques es de 100 ms y la latencia de un toque es de 150 ms, el importe de más de 50 ms para esa interacción sería de 50 ms. Luego, podríamos calcular la cantidad máxima de latencia que supera el presupuesto para cualquier interacción del usuario en la página.

Otra opción es calcular la latencia promedio o mediana de las interacciones durante la vida útil de la página. Entonces, si tuviéramos latencias de 80 ms, 90 ms y 100 ms, la latencia promedio de la página sería de 90 ms. También podríamos considerar el promedio o la mediana de "sobre el presupuesto" para tener en cuenta las diferentes expectativas según el tipo de interacción.

¿Cómo se ve esto en las APIs de rendimiento web?

¿Qué falta en la función Tiempos de eventos?

Lamentablemente, no todas las ideas que se presentan en esta publicación se pueden recopilar con la API de Event Timing. En particular, no hay una forma sencilla de conocer los eventos asociados con una interacción del usuario determinada con la API. Para ello, proponemos agregar un interactionID a la API.

Otra deficiencia de la API de Event Timing es que no hay manera de medir la interacción de desplazamiento, por lo que estamos trabajando para habilitar estas mediciones (a través de Event Timing o una API separada).

¿Qué puedes probar ahora mismo?

En este momento, todavía es posible calcular la latencia máxima para presionar y arrastrar y para las interacciones del teclado. El siguiente fragmento de código produciría estas dos 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.

Comentarios

Envía un correo electrónico a web-vitals-feedback@googlegroups.com para conocer tu opinión sobre estas ideas.