API de Long Animation Frames

La API de Long Animation Frames (LoAF, que se pronuncia Lo-Af) es una actualización de la API de Long Tasks para proporcionar una mejor comprensión de las actualizaciones lentas de la interfaz de usuario (IU). Esto puede ser útil para identificar fotogramas de animación lentos que probablemente afecten la métrica de interacción a la siguiente pintura (INP) de las métricas web esenciales, que mide la capacidad de respuesta, o para identificar otros bloqueos de la IU que afectan la fluidez.

Estado de la API

Navegadores compatibles

  • Chrome: 123.
  • Edge: 123.
  • Firefox: No es compatible.
  • Safari: No se admite.

Origen

Después de una prueba de origen de Chrome 116 a Chrome 122, la API de LoAF se lanzó desde Chrome 123.

En segundo plano: la API de Long Tasks

Navegadores compatibles

  • Chrome: 58.
  • Edge: 79.
  • Firefox: No es compatible.
  • Safari: No se admite.

Origen

La API de Long Animation Frames es una alternativa a la API de Long Tasks, que está disponible en Chrome desde hace algún tiempo (desde Chrome 58). Como su nombre lo indica, la API de Long Task te permite supervisar tareas largas, que son tareas que ocupan el subproceso principal durante 50 milisegundos o más. Las tareas largas se pueden supervisar con la interfaz PerformanceLongTaskTiming, con un PeformanceObserver:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'longtask', buffered: true });

Es probable que las tareas largas causen problemas de capacidad de respuesta. Si un usuario intenta interactuar con una página (por ejemplo, hacer clic en un botón o abrir un menú), pero el subproceso principal ya está ocupado con una tarea larga, la interacción del usuario se retrasa hasta que se complete esa tarea.

Para mejorar la capacidad de respuesta, a menudo se recomienda dividir las tareas largas. Si cada tarea larga se divide en una serie de varias tareas más pequeñas, es posible que se ejecuten tareas más importantes entre ellas para evitar demoras significativas en la respuesta a las interacciones.

Por lo tanto, cuando se intenta mejorar la capacidad de respuesta, el primer esfuerzo suele ser ejecutar un seguimiento de rendimiento y observar las tareas largas. Esto puede ser a través de una herramienta de auditoría basada en el laboratorio, como Lighthouse (que tiene una auditoría Evitar tareas largas en el subproceso principal), o analizando las tareas largas en las Herramientas para desarrolladores de Chrome.

Las pruebas basadas en laboratorios a menudo son un mal punto de partida para identificar problemas de capacidad de respuesta, ya que es posible que estas herramientas no incluyan interacciones. Cuando lo hacen, se trata de un subconjunto pequeño de interacciones probables. Lo ideal sería que midieras las causas de las interacciones lentas en el campo.

Desventajas de la API de Long Tasks

Medir tareas largas en el campo con un observador de rendimiento solo es útil en cierta medida. En realidad, no proporciona mucha información más allá del hecho de que se realizó una tarea larga y cuánto tiempo tardó.

Las herramientas de supervisión de usuarios reales (RUM) suelen usar esto para determinar la tendencia de la cantidad o la duración de las tareas largas, o para identificar en qué páginas ocurren. Sin embargo, sin los detalles subyacentes de lo que causó la tarea larga, esto tiene un uso limitado. La API de Long Tasks solo tiene un modelo de atribución básico, que, en el mejor de los casos, solo te indica el contenedor en el que se produjo la tarea larga (el documento de nivel superior o un <iframe>), pero no la secuencia de comandos o la función que la llamó, como se muestra en una entrada típica:

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

La API de Long Tasks también es una vista incompleta, ya que también puede excluir algunas tareas importantes. Algunas actualizaciones, como la renderización, se producen en tareas independientes que, idealmente, deberían incluirse junto con la ejecución anterior que causó esa actualización para medir con precisión el "trabajo total" de esa interacción. Para obtener más detalles sobre las limitaciones de depender de las tareas, consulta la sección "Dónde no alcanzan las tareas largas" de la explicación.

El último problema es que la medición de tareas largas solo informa sobre tareas individuales que tardan más que el límite de 50 milisegundos. Un fotograma de animación puede estar compuesto por varias tareas más pequeñas que este límite de 50 milisegundos, pero, en conjunto, aún bloquean la capacidad de renderización del navegador.

La API de Long Animation Frames

Navegadores compatibles

  • Chrome: 123.
  • Edge: 123.
  • Firefox: No es compatible.
  • Safari: No se admite.

Origen

La API de Long Animation Frames (LoAF) es una API nueva que busca abordar algunas de las deficiencias de la API de Long Tasks para permitir que los desarrolladores obtengan estadísticas más prácticas que ayuden a abordar los problemas de capacidad de respuesta y mejorar la INP, así como obtener estadísticas sobre los problemas de fluidez.

Una buena capacidad de respuesta significa que una página responde rápidamente a las interacciones que se realizan con ella. Esto implica poder pintar las actualizaciones que el usuario necesita de forma oportuna y evitar que se bloqueen. En el caso de los INP, se recomienda responder en 200 milisegundos o menos, pero para otras actualizaciones (por ejemplo, animaciones), incluso 200 milisegundos pueden ser demasiado largos.

La API de Long Animation Frames es un enfoque alternativo para medir el trabajo de bloqueo. En lugar de medir las tareas individuales, la API de Long Animation Frames, como su nombre lo sugiere, mide los marcos de animación largos. Un fotograma de animación largo se produce cuando una actualización de renderización se retrasa más de 50 milisegundos (el mismo umbral que el de la API de Long Tasks).

Los fotogramas de animación largos se miden desde el inicio de las tareas que requieren una renderización. Cuando la primera tarea en un posible fotograma de animación larga no requiere una renderización, el fotograma de animación larga finaliza cuando se completa la tarea sin renderización y se inicia un nuevo fotograma de animación larga potencial con la siguiente tarea. Estos fotogramas de animación larga que no se renderizan aún se incluyen en la API de Long Animation Frames cuando son superiores a 50 milisegundos (con un tiempo de renderStart de 0) para permitir la medición del trabajo potencialmente bloqueador.

Los fotogramas de animación largos se pueden observar de manera similar a las tareas largas con un PerformanceObserver, pero en su lugar, se observa el tipo long-animation-frame:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'long-animation-frame', buffered: true });

Los fotogramas de animación largos anteriores también se pueden consultar desde el Cronograma de rendimiento de la siguiente manera:

const loafs = performance.getEntriesByType('long-animation-frame');

Sin embargo, hay un maxBufferSize para las entradas de rendimiento después del cual se descartan las entradas más recientes, por lo que el enfoque de PerformanceObserver es el recomendado. El tamaño del búfer de long-animation-frame se establece en 200, al igual que para long-tasks.

Ventajas de observar marcos en lugar de tareas

La ventaja clave de observar esto desde una perspectiva de fotogramas en lugar de una perspectiva de tareas es que una animación larga puede estar compuesta por cualquier cantidad de tareas que, de forma acumulativa, generen un fotograma de animación largo. Esto aborda el último punto mencionado anteriormente, en el que es posible que la API de Long Tasks no muestre la suma de muchas tareas más pequeñas que bloquean la renderización antes de un fotograma de animación.

Otra ventaja de esta vista alternativa en tareas largas es la capacidad de proporcionar desgloses de tiempos de todo el fotograma. En lugar de incluir solo un startTime y un duration, como la API de Long Tasks, LoAF incluye un desglose mucho más detallado de las diferentes partes de la duración del fotograma.

Marcas de tiempo y duraciones de fotogramas

  • startTime: Es la hora de inicio del fotograma de animación largo en relación con la hora de inicio de la navegación.
  • duration: Es la duración del fotograma de animación largo (sin incluir el tiempo de presentación).
  • renderStart: Es la hora de inicio del ciclo de renderización, que incluye devoluciones de llamada de requestAnimationFrame, cálculo de diseño y estilo, y devoluciones de llamada de observador de intersección y observador de cambio de tamaño.
  • styleAndLayoutStart: Es el comienzo del período dedicado a los cálculos de diseño y estilo.
  • firstUIEventTimestamp: Es la hora del primer evento de IU (mouse/teclado, etcétera) que se controlará durante el transcurso de este fotograma.
  • blockingDuration: Es la duración total en milisegundos durante la cual el fotograma de animación bloquearía el procesamiento de la entrada o de otras tareas de alta prioridad.

Una explicación de blockingDuration

Un fotograma de animación largo puede estar compuesto por varias tareas. blockingDuration es la suma de las duraciones de las tareas superiores a 50 milisegundos (incluida la duración de renderización final dentro de la tarea más larga).

Por ejemplo, si un fotograma de animación largo estuviera compuesto por dos tareas de 55 milisegundos y 65 milisegundos, seguidas de una renderización de 20 milisegundos, el duration sería de aproximadamente 140 milisegundos con un blockingDuration de (55 - 50) + (65 + 20 - 50) = 40 milisegundos. Durante 40 milisegundos de este fotograma de animación de 140 milisegundos, se consideró que el fotograma estaba bloqueado para controlar la entrada.

Si se debe mirar duration o blockingDuration

En el caso de la pantalla común de 60 hercios, un navegador intentará programar un fotograma al menos cada 16.66 milisegundos (para garantizar actualizaciones fluidas) o después de una tarea de alta prioridad, como el manejo de entradas (para garantizar actualizaciones responsivas). Sin embargo, si no hay entradas ni otras tareas de alta prioridad, pero hay una cola de otras tareas, el navegador suele continuar con el fotograma actual mucho más allá de los 16.66 milisegundos, sin importar qué tan bien estén divididas las tareas en él. Es decir, el navegador siempre intentará priorizar las entradas, pero puede optar por abordar una cola de tareas en lugar de actualizaciones de renderización. Esto se debe a que la renderización es un proceso costoso, por lo que procesar una tarea de renderización combinada para varias tareas suele generar una reducción general del trabajo.

Por lo tanto, los fotogramas de animación largos con un blockingDuration bajo o nulo deberían seguir siendo responsivos a la entrada. Por lo tanto, reducir o eliminar blockingDuration dividiendo las tareas largas es clave para mejorar la capacidad de respuesta, medida por la INP.

Sin embargo, muchos fotogramas de animación largos, independientemente de blockingDuration, indican que las actualizaciones de la IU están retrasadas y, por lo tanto, pueden afectar la fluidez y generar la sensación de una interfaz de usuario con retrasos para el desplazamiento o las animaciones, incluso si estos son menos un problema para la capacidad de respuesta, como se mide con INP. Para comprender los problemas en esta área, observa el duration, pero estos pueden ser más difíciles de optimizar, ya que no puedes resolverlos dividiendo el trabajo, sino que debes reducirlo.

Tiempos de fotogramas

Las marcas de tiempo mencionadas anteriormente permiten que el fotograma de animación largo se divida en tiempos:

Tiempos Cálculo
Hora de inicio startTime
Hora de finalización startTime + duration
Duración del trabajo renderStart ? renderStart - startTime : duration
Duración del procesamiento renderStart ? (startTime + duration) - renderStart: 0
Renderización: Duración previa al diseño styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Renderización: Duración del estilo y el diseño styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Mejor atribución de secuencias de comandos

El tipo de entrada long-animation-frame incluye mejores datos de atribución de cada secuencia de comandos que contribuyó a un fotograma de animación largo (para secuencias de comandos de más de 5 milisegundos).

Al igual que con la API de Long Tasks, se proporcionará en un array de entradas de atribución, cada una de las cuales detalla lo siguiente:

  • Un name y un EntryType mostrarán script.
  • Un invoker significativo que indica cómo se llamó a la secuencia de comandos (por ejemplo, 'IMG#id.onload', 'Window.requestAnimationFrame' o 'Response.json.then').
  • El invokerType del punto de entrada de la secuencia de comandos:
    • user-callback: Es una devolución de llamada conocida registrada desde una API de plataforma web (por ejemplo, setTimeout, requestAnimationFrame).
    • event-listener: Es un objeto de escucha de un evento de la plataforma (por ejemplo, click, load, keyup).
    • resolve-promise: Controlador de una promesa de plataforma (por ejemplo, fetch()). Ten en cuenta que, en el caso de las promesas, todos los controladores de las mismas promesas se mezclan como una "secuencia de comandos")..
    • reject-promise: Es similar a resolve-promise, pero para el rechazo.
    • classic-script: Evaluación de la secuencia de comandos (por ejemplo, <script> o import())
    • module-script: Igual que classic-script, pero para secuencias de comandos de módulos.
  • Datos de tiempo separados para esa secuencia de comandos:
    • startTime: Es la hora en la que se invocó la función de entrada.
    • duration: Es la duración entre startTime y el momento en que se termina de procesar la cola de microtareas posterior.
    • executionStart: Es la hora después de la compilación.
    • forcedStyleAndLayoutDuration: Es el tiempo total dedicado a procesar el diseño y el estilo forzados dentro de esta función (consulta fragmentación).
    • pauseDuration: Es el tiempo total dedicado a "pausar" operaciones síncronas (alerta, XHR síncrona).
  • Detalles de la fuente de la secuencia de comandos:
    • sourceURL: Es el nombre del recurso de la secuencia de comandos cuando está disponible (o está vacío si no se encuentra).
    • sourceFunctionName: Es el nombre de la función de la secuencia de comandos cuando está disponible (o está vacío si no se encuentra).
    • sourceCharPosition: Es la posición del carácter de la secuencia de comandos cuando está disponible (o -1 si no se encuentra).
  • windowAttribution: Es el contenedor (el documento de nivel superior o un <iframe>) en el que se produjo el fotograma de animación largo.
  • window: Es una referencia a la ventana del mismo origen.

Cuando se proporcionan, las entradas de origen permiten que los desarrolladores sepan exactamente cómo se llamó a cada secuencia de comandos en el fotograma de animación largo, hasta la posición del carácter en la secuencia de comandos de llamada. Esto proporciona la ubicación exacta en un recurso de JavaScript que generó el fotograma de animación largo.

Ejemplo de una entrada de rendimiento de long-animation-frame

Un ejemplo completo de entrada de rendimiento de long-animation-frame, que contiene una sola secuencia de comandos, es el siguiente:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

Como se puede ver, esto proporciona una cantidad sin precedentes de datos para que los sitios web puedan comprender la causa de las actualizaciones de renderización con retraso.

Usa la API de Long Animation Frames en el campo

Herramientas como las Herramientas para desarrolladores de Chrome y Lighthouse, si bien son útiles para descubrir y reproducir problemas, son herramientas de laboratorio que pueden pasar por alto aspectos importantes de la experiencia del usuario que solo los datos de campo pueden proporcionar.

La API de Long Animation Frames está diseñada para usarse en el campo y recopilar datos contextuales importantes para las interacciones del usuario que la API de Long Tasks no podía. Esto puede ayudarte a identificar y reproducir problemas de interactividad que, de otro modo, podrías no haber descubierto.

Compatibilidad con la API de Feature Detecting Long Animation Frames

Puedes usar el siguiente código para probar si la API es compatible:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

El caso de uso más obvio de la API de Long Animation Frames es ayudar a diagnosticar y corregir problemas de Interaction to Next Paint (INP), y esa fue una de las razones clave por las que el equipo de Chrome desarrolló esta API. Una buena INP es aquella en la que se responde a todas las interacciones en 200 milisegundos o menos desde la interacción hasta que se pinta el fotograma. Dado que la API de Long Animation Frames mide todos los fotogramas que tardan 50 ms o más, la mayoría de las INP problemáticas deben incluir datos de LoAF para ayudarte a diagnosticar esas interacciones.

El "LoAF de INP" es el LoAF que incluye la interacción de INP, como se muestra en el siguiente diagrama:

Ejemplos de fotogramas de animación largos en una página, con el LoAF de INP destacado.
Una página puede tener muchos LoAF, uno de los cuales está relacionado con la interacción de INP.

En algunos casos, es posible que un evento de INP abarque dos LoAF, por lo general, si la interacción se produce después de que el fotograma inició la parte de renderización del fotograma anterior, por lo que el controlador de eventos se procesa en el siguiente fotograma:

Ejemplos de fotogramas de animación largos en una página, con el LoAF de INP destacado.
Una página puede tener muchos LoAF, uno de los cuales está relacionado con la interacción de INP.

Incluso es posible que abarque más de dos LoAF en algunas circunstancias excepcionales.

Si registras los datos de LoAF asociados con la interacción de INP, puedes obtener mucha más información sobre la interacción de INP para ayudar a diagnosticarla. Esto es particularmente útil para comprender el retardo de entrada, ya que puedes ver qué otras secuencias de comandos se estaban ejecutando en ese fotograma.

También puede ser útil comprender la duración del procesamiento y la demora de la presentación inexplicables si tus controladores de eventos no reproducen los valores que se ven para ellos, ya que es posible que se estén ejecutando otras secuencias de comandos para tus usuarios que no se incluyen en tus propias pruebas.

No hay una API directa para vincular una entrada de INP con sus entradas de LoAF relacionadas, aunque es posible hacerlo en el código comparando las horas de inicio y finalización de cada una (consulta la WhyNp). La biblioteca web-vitals incluye todos los LoAF que se cruzan en la propiedad longAnimationFramesEntries de la interfaz de atribución de INP a partir de la versión 4.

Una vez que hayas vinculado las entradas de LoAF, podrás incluir información con la atribución de INP. El objeto scripts contiene algunos de los datos más valiosos, ya que puede mostrar qué más se estaba ejecutando en esos fotogramas, por lo que enviar esos datos a tu servicio de estadísticas te permitirá comprender mejor por qué las interacciones fueron lentas.

Informar los LoAF para la interacción de INP es una buena manera de encontrar los problemas de interactividad más urgentes en tu página. Cada usuario puede interactuar de manera diferente con tu página y, con un volumen suficiente de datos de atribución de INP, se incluirán algunos problemas potenciales en los datos de atribución de INP. Esto te permite ordenar las secuencias de comandos por volumen para ver cuáles se correlacionan con una INP lenta.

Cómo informar más datos de animación de larga duración a un extremo de estadísticas

Una desventaja de solo mirar los LoAF de INP es que podrías pasar por alto otras áreas potenciales de mejora que podrían causar problemas de INP en el futuro. Esto puede generar la sensación de estar dando vueltas en círculos, ya que corriges un problema de INP con la expectativa de ver una gran mejora, solo para descubrir que la siguiente interacción más lenta es solo un poco mejor que esa, por lo que tu INP no mejora mucho.

Por lo tanto, en lugar de solo mirar el LoAF de INP, te recomendamos que consideres todos los LoAF durante el ciclo de vida de la página:

Una página con muchos LoAF, algunos de los cuales ocurren durante las interacciones, incluso si no es la interacción de INP.
Observar todos los LoAF puede ayudar a identificar problemas de INP futuros.

Sin embargo, cada entrada de LoAF contiene datos considerables, por lo que es probable que desees restringir tu análisis a solo algunos LoAF. Además, como las entradas de fotogramas de animación largos pueden ser bastante grandes, los desarrolladores deben decidir qué datos de la entrada se deben enviar a Analytics. Por ejemplo, los tiempos de resumen de la entrada y, tal vez, los nombres de las secuencias de comandos, o algún otro conjunto mínimo de otros datos contextuales que se consideren necesarios.

Estos son algunos patrones sugeridos para reducir la cantidad de datos de fotogramas de animación largos:

Cuál de estos patrones funciona mejor para ti depende de qué tan avanzado estés en tu recorrido de optimización y de qué tan comunes sean los fotogramas de animación largos. En el caso de un sitio que nunca antes se optimizó para la capacidad de respuesta, es posible que haya muchos LoAF. Te recomendamos que te limites a los LoAF con interacciones, que establezcas un umbral alto o que solo mires los peores.

A medida que resuelvas los problemas de capacidad de respuesta comunes, puedes expandir esta opción si no te limitas solo a las interacciones o a las duraciones de bloqueo altas, o si reduces los umbrales.

Observa fotogramas de animación largos con interacciones

Para obtener estadísticas más allá del fotograma de animación larga de INP, puedes observar todos los LoAF con interacciones (que se pueden detectar por la presencia de un valor firstUIEventTimestamp) con un blockingDuration alto.

Este también puede ser un método más sencillo para supervisar los LoAF de INP en lugar de intentar correlacionar los dos, lo que puede ser más complejo. En la mayoría de los casos, esto incluirá la LoAF de INP para una visita determinada y, en los casos excepcionales en los que no lo haga, aún se mostrarán interacciones largas que es importante corregir, ya que pueden ser la interacción de INP para otros usuarios.

El siguiente código registra todas las entradas de LoAF con un blockingDuration superior a 100 milisegundos en las que se produjo una interacción durante el fotograma. Se eligió 100 porque es inferior al umbral de INP "bueno" de 200 milisegundos. Puedes elegir un valor más alto o más bajo según tus necesidades.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
      entry.firstUIEventTimestamp > 0
    ) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Observa fotogramas de animación largos con duraciones de bloqueo altas

Como mejora para ver todos los fotogramas de animación largos con interacciones, te recomendamos que mires todos los fotogramas de animación largos con duraciones de bloqueo altas. Estos indican posibles problemas de INP si un usuario interactúa durante estos fotogramas de animación largos.

El siguiente código registra todas las entradas de LoAF con una duración de bloqueo superior a 100 milisegundos en las que se produjo una interacción durante el fotograma. Se eligió 100 porque es inferior al umbral de INP "bueno" de 200 milisegundos para ayudar a identificar posibles fotogramas problemáticos, a la vez que se mantiene al mínimo la cantidad de fotogramas de animación largos informados. Puedes elegir un valor más alto o más bajo según tus necesidades.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Observa fotogramas de animación largos durante las actualizaciones críticas de la IU para mejorar la fluidez

Como se mencionó anteriormente, observar los fotogramas de animación largos con una duración de bloqueo alta puede ayudar a abordar la capacidad de respuesta de la entrada. Sin embargo, para que sea fluida, debes observar todos los fotogramas de animación largos con un duration largo.

Dado que esto puede generar mucho ruido, te recomendamos que restrinjas las mediciones a puntos clave con un patrón como el siguiente:

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  if (measureImportantUIupdate) {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

async function doUIUpdatesWithMeasurements() {
  measureImportantUIupdate = true;
  await doUIUpdates();
  measureImportantUIupdate = false;
}

Observa los peores fotogramas de animación largos

En lugar de tener un umbral establecido, es posible que los sitios deseen recopilar datos sobre el fotograma (o los fotogramas) de animación más largo para reducir el volumen de datos que se deben enviar a los píxeles contadores. Por lo tanto, no importa cuántos fotogramas de animación largos experimente una página, solo se envían los datos de los peores cinco, diez o la cantidad de fotogramas de animación largos que sean absolutamente necesarios.

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Estas estrategias también se pueden combinar. Solo observa los 10 peores LoAF, con interacciones de más de 100 milisegundos.

En el momento adecuado (idealmente, en el evento visibilitychange), el píxel contador vuelve a Analytics. Para realizar pruebas locales, puedes usar console.table de forma periódica:

console.table(longestBlockingLoAFs);

Identifica patrones comunes en fotogramas de animación largos

Una estrategia alternativa sería observar las secuencias de comandos comunes que aparecen más en las entradas de fotogramas de animación largos. Los datos se pueden informar a nivel de la secuencia de comandos y la posición de los caracteres para identificar a los infractores reincidentes.

Esto puede funcionar muy bien en plataformas personalizables en las que se pueden identificar temas o complementos que causan problemas de rendimiento en varios sitios.

El tiempo de ejecución de secuencias de comandos comunes (o orígenes de terceros) en fotogramas de animación largos se podría resumir y volver a informar para identificar los factores comunes que generan fotogramas de animación largos en un sitio o una colección de sitios. Por ejemplo, para ver las URLs:

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

Un ejemplo de este resultado es el siguiente:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

Usa la API de Long Animation Frames en las herramientas

La API también permite herramientas adicionales para desarrolladores para la depuración local. Si bien algunas herramientas, como Lighthouse y las herramientas para desarrolladores de Chrome, pudieron recopilar muchos de estos datos con detalles de seguimiento de nivel inferior, tener esta API de nivel superior podría permitir que otras herramientas accedan a estos datos.

Muestra datos de fotogramas de animación largos en DevTools

Puedes mostrar fotogramas de animación largos en DevTools con la API de performance.measure(), que luego se muestran en el segmento de tiempos de usuario de DevTools en los seguimientos de rendimiento para mostrar dónde debes enfocar tus esfuerzos para mejorar el rendimiento. Con la API de Extensibility de DevTools, incluso se pueden mostrar en su propio segmento:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
      detail: {
        devtools: {
          dataType: "track-entry",
          track: "Long animation frames",
          trackGroup: "Performance Timeline",
          color: "tertiary-dark",
          tooltipText: 'LoAF'
        }
      }
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
Registro del panel de rendimiento de DevTools con una pista personalizada que muestra datos de fotogramas de animación largos que se pueden comparar con el gráfico de llama principal.
Se muestran datos de fotogramas de animación largos en DevTools.

A largo plazo, es probable que los fotogramas de animación largos se incorporen en las Herramientas para desarrolladores, pero el fragmento de código anterior permite que se muestren allí mientras tanto.

La primera entrada de la figura anterior también muestra dónde el navegador procesó varias tareas juntas en el mismo fotograma de animación largo en lugar de renderizar entre ellas. Como se mencionó anteriormente, esto puede ocurrir cuando no hay tareas de entrada de alta prioridad, pero hay una cola de tareas. La primera tarea larga tiene algunas actualizaciones de renderización para completar (de lo contrario, el fotograma de animación largo actual se restablecería después y comenzaría uno nuevo con la siguiente tarea), pero en lugar de realizar esa acción de renderización de inmediato, el navegador procesó varias tareas adicionales y solo entonces realizó la acción de renderización larga y finalizó el fotograma de animación largo. Esto demuestra la utilidad de observar fotogramas de animación largos en DevTools, en lugar de solo tareas largas, para ayudar a identificar renderizaciones demoradas.

Usa datos de fotogramas de animación largos en otras herramientas para desarrolladores

La extensión de métricas web esenciales mostró el valor en la información de depuración del resumen de registro para diagnosticar problemas de rendimiento.

Ahora también muestra datos de fotogramas de animación largos para cada devolución de llamada de INP y cada interacción:

Registro de la consola de la extensión de Métricas web
La consola de la extensión de Métricas web muestra datos de LoAF.

Usa datos de fotogramas de animación largos en herramientas de prueba automatizadas

Del mismo modo, las herramientas de pruebas automatizadas en las canalización de CI/CD pueden mostrar detalles sobre posibles problemas de rendimiento midiendo fotogramas de animación largos mientras se ejecutan varios paquetes de prueba.

Preguntas frecuentes

Estas son algunas de las preguntas frecuentes sobre esta API:

¿Por qué no extender o iterar en la API de Long Tasks?

Esta es una forma alternativa de informar una medición similar, pero en última instancia diferente, de los posibles problemas de capacidad de respuesta. Es importante garantizar que los sitios que dependen de la API de tareas largas existente sigan funcionando para evitar interrumpir los casos de uso existentes.

Si bien la API de Long Tasks puede beneficiarse de algunas de las funciones de LoAF (como un mejor modelo de atribución), creemos que enfocarse en los fotogramas en lugar de las tareas ofrece muchos beneficios que hacen que esta sea una API fundamentalmente diferente de la API de Long Tasks existente.

¿Por qué no tengo entradas de secuencia de comandos?

Esto puede indicar que el fotograma de animación largo no se debió a JavaScipt, sino a un trabajo de renderización grande.

Esto también puede ocurrir cuando el fotograma de animación largo es debido a JavaScript, pero la atribución de la secuencia de comandos no se puede proporcionar por varios motivos de privacidad, como se señaló anteriormente (principalmente, que la página no es propietaria de JavaScript).

¿Por qué tengo entradas de secuencias de comandos, pero no hay información de la fuente o es limitada?

Esto puede deberse a varios motivos, entre los que se incluye que no hay una buena fuente a la que hacer referencia.

La información de la secuencia de comandos también se limitará solo a sourceURL (sin incluir redireccionamientos) para las secuencias de comandos no-cors cross-origin, con una cadena vacía para sourceFunctionName y un -1 para sourceCharPosition. Para resolver este problema, recupera esas secuencias de comandos con CORS y agrega crossOrigin = "anonymous" a la llamada <script>.

Por ejemplo, la secuencia de comandos predeterminada de Google Tag Manager que se agrega a la página:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

Se puede mejorar para agregar j.crossOrigin = "anonymous" y permitir que se proporcionen detalles de atribución completos para GTM.

¿Esto reemplazará a la API de Long Tasks?

Si bien creemos que la API de Long Animation Frames es una API mejor y más completa para medir tareas largas, por el momento, no hay planes para dar de baja la API de Long Tasks.

Se solicitan comentarios

Puedes enviar comentarios en la lista de problemas de GitHub o informar errores en la implementación de la API de Chrome en el seguimiento de problemas de Chrome.

Conclusión

La API de Long Animation Frames es una nueva API emocionante con muchas ventajas potenciales sobre la API de Long Tasks anterior.

Se está demostrando como una herramienta clave para abordar los problemas de capacidad de respuesta, según lo mide el INP. El INP es una métrica difícil de optimizar, y esta API es una forma en que el equipo de Chrome busca facilitar a los desarrolladores la identificación y solución de problemas.

Sin embargo, el alcance de la API de Long Animation Frames se extiende más allá de INP y puede ayudar a identificar otras causas de actualizaciones lentas que pueden afectar la fluidez general de la experiencia del usuario de un sitio web.

Agradecimientos

Imagen en miniatura de Henry Be en Unsplash.