API Long Animation Frames

L'API Long Animation Frames (LoAF, prononcée "Lo-Af") est une mise à jour de l'API Long Tasks qui permet de mieux comprendre les mises à jour lentes de l'interface utilisateur (UI). Cela peut être utile pour identifier les images d'animation lentes susceptibles d'affecter la métrique Core Web Vitals Interaction to Next Paint (INP), qui mesure la réactivité, ou pour identifier d'autres à-coups de l'interface utilisateur qui affectent la lissage.

État de l'API

Navigateurs pris en charge

  • Chrome: 123
  • Edge : 123.
  • Firefox : non compatible.
  • Safari: non compatible.

Source

Après une phase d'évaluation de l'origine de Chrome 116 à Chrome 122, l'API LoAF a été publiée à partir de Chrome 123.

Contexte : l'API Long Tasks

Navigateurs pris en charge

  • Chrome : 58.
  • Edge : 79.
  • Firefox : non compatible.
  • Safari : non compatible.

Source

L'API Long Animation Frames est une alternative à l'API Long Tasks, qui est disponible dans Chrome depuis un certain temps (depuis Chrome 58). Comme son nom l'indique, l'API Long Task vous permet de surveiller les tâches longues, c'est-à-dire celles qui occupent le thread principal pendant au moins 50 millisecondes. Vous pouvez surveiller les tâches longues à l'aide de l'interface PerformanceLongTaskTiming, avec un PeformanceObserver:

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

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

Les tâches longues sont susceptibles de provoquer des problèmes de réactivité. Si un utilisateur tente d'interagir avec une page (par exemple, cliquer sur un bouton ou ouvrir un menu), mais que le thread principal s'occupe déjà d'une tâche longue, l'interaction de l'utilisateur est retardée en attendant que cette tâche soit terminée.

Pour améliorer la réactivité, il est souvent conseillé de décomposer les tâches longues. Si chaque tâche longue est décomposée en plusieurs tâches plus petites, il est possible que des tâches plus importantes puissent être exécutées entre elles pour éviter des retards importants dans la réponse aux interactions.

Par conséquent, lorsque vous essayez d'améliorer la réactivité, la première étape consiste souvent à exécuter une trace de performances et à examiner les tâches longues. Vous pouvez le faire à l'aide d'un outil d'audit en laboratoire tel que Lighthouse (qui propose un audit Éviter les longues tâches du thread principal), ou en examinant les tâches longues dans les outils pour les développeurs Chrome.

Les tests en laboratoire sont souvent un mauvais point de départ pour identifier les problèmes de réactivité, car ces outils peuvent ne pas inclure d'interactions. S'ils le font, il s'agit d'un petit sous-ensemble d'interactions probables. Dans l'idéal, vous devriez mesurer les causes des interactions lentes sur le terrain.

Inconvénients de l'API Long Tasks

Mesurer des tâches longues sur le terrain à l'aide d'un observateur de performances n'est que partiellement utile. En réalité, il ne fournit pas beaucoup d'informations, si ce n'est que la tâche a été longue et la durée qu'elle a prise.

Les outils de surveillance des utilisateurs réels (RUM) utilisent souvent cette métrique pour suivre l'évolution du nombre ou de la durée des tâches longues, ou pour identifier les pages sur lesquelles elles se produisent. Toutefois, sans les détails sous-jacents sur la cause de la tâche longue, cette métrique n'est que d'une utilité limitée. L'API Long Tasks ne dispose que d'un modèle d'attribution de base, qui ne vous indique au mieux que le conteneur dans lequel la tâche longue s'est produite (le document de niveau supérieur ou un <iframe>), mais pas le script ou la fonction qui l'ont appelée, comme le montre une entrée typique :

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

L'API Long Tasks est également incomplète, car elle peut également exclure certaines tâches importantes. Certaines mises à jour, comme le rendu, se produisent dans des tâches distinctes qui devraient idéalement être incluses avec l'exécution précédente à l'origine de cette mise à jour afin de mesurer précisément le "travail total" de cette interaction. Pour en savoir plus sur les limites des tâches, consultez la section "Où les tâches longues échouent" de la vidéo explicative.

Le dernier problème est que la mesure des tâches longues ne fournit des rapports que sur les tâches individuelles qui durent plus de 50 millisecondes. Un frame d'animation peut être composé de plusieurs tâches inférieures à cette limite de 50 millisecondes, mais bloquer collectivement la capacité de rendu du navigateur.

API Long Animation Frames

Navigateurs pris en charge

  • Chrome : 123.
  • Edge: 123
  • Firefox : non compatible.
  • Safari : non compatible.

Source

L'API Long Animation Frames (LoAF) est une nouvelle API qui vise à combler certaines des lacunes de l'API Long Tasks. Elle permet aux développeurs d'obtenir des insights plus exploitables afin de résoudre les problèmes de réactivité et d'améliorer l'INP, ainsi que de mieux comprendre les problèmes de fluidité.

Une bonne réactivité signifie qu'une page répond rapidement aux interactions avec elle. Cela implique de pouvoir peindre toutes les mises à jour nécessaires à l'utilisateur dans les meilleurs délais et d'éviter de bloquer ces mises à jour. Pour les INP, nous vous recommandons de répondre en 200 millisecondes ou moins, mais pour d'autres mises à jour (animations, par exemple), même 200 millisecondes peuvent être trop longues.

L'API Long Animation Frames est une autre approche pour mesurer le travail bloquant. Plutôt que de mesurer les tâches individuelles, l'API Long Animation Frames (comme son nom l'indique) mesure les frames d'animation longs. Un frame d'animation long se produit lorsqu'une mise à jour de rendu est retardée de plus de 50 millisecondes (même seuil que celui de l'API Long Tasks).

Les images d'animation longues sont mesurées à partir du début des tâches qui nécessitent un rendu. Si la première tâche d'un frame d'animation long potentiel ne nécessite pas de rendu, le frame d'animation long est terminé à la fin de la tâche sans rendu, et un nouveau frame d'animation long potentiel est lancé avec la tâche suivante. Ces images d'animation longues sans rendu sont toujours incluses dans l'API Long Animation Frames lorsqu'elles durent plus de 50 millisecondes (avec une durée renderStart de 0) afin de permettre de mesurer le travail potentiellement bloquant.

Les longues frames d'animation peuvent être observées de la même manière que les tâches longues avec un PerformanceObserver, mais en examinant le type long-animation-frame à la place:

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

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

Vous pouvez également interroger les images d'animation longues précédentes à partir de la timeline des performances comme suit :

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

Toutefois, il existe un maxBufferSize pour les entrées de performances, après quoi les entrées plus récentes sont supprimées. L'approche PerformanceObserver est donc recommandée. La taille de la mémoire tampon long-animation-frame est définie sur 200, comme pour long-tasks.

Avantages de l'analyse des frames au lieu des tâches

Le principal avantage d'examiner cela du point de vue d'une image plutôt que du point de vue des tâches est qu'une longue animation peut être composée de n'importe quel nombre de tâches ayant entraîné une longue image d'animation. Cela répond au dernier point mentionné précédemment, où la somme de nombreuses petites tâches bloquant le rendu avant un frame d'animation peut ne pas être affichée par l'API Long Tasks.

Autre avantage de cette vue alternative des tâches longues : vous pouvez obtenir une répartition temporelle de l'ensemble du frame. Au lieu d'inclure uniquement un startTime et un duration, comme l'API Long Tasks, LoAF inclut une répartition beaucoup plus détaillée des différentes parties de la durée du frame.

Codes temporels et durées des frames

  • startTime : heure de début du frame d'animation longue par rapport à l'heure de début de la navigation.
  • duration : durée du frame d'animation long (sans compter le temps de présentation).
  • renderStart : heure de début du cycle de rendu, qui comprend les rappels requestAnimationFrame, le calcul du style et de la mise en page, les rappels de l'observateur de redimensionnement et de l'observateur d'intersection.
  • styleAndLayoutStart: début de la période de calcul du style et de la mise en page.
  • firstUIEventTimestamp : heure du premier événement d'interface utilisateur (souris/clavier, etc.) à traiter au cours de ce frame.
  • blockingDuration: durée totale en millisecondes pendant laquelle le frame d'animation bloque le traitement de l'entrée ou d'autres tâches de priorité élevée.

Explication de blockingDuration

Un frame d'animation long peut être composé de plusieurs tâches. blockingDuration correspond à la somme des durées de tâche supérieures à 50 millisecondes (y compris la durée de rendu finale de la tâche la plus longue).

Par exemple, si une longue image d'animation était composée de deux tâches de 55 millisecondes et 65 millisecondes, suivies d'un rendu de 20 millisecondes, duration serait d'environ 140 millisecondes avec une blockingDuration de (55 - 50) + (65 + 20 - 50) = 40 millisecondes. Pendant 40 millisecondes de ce frame d'animation de 140 millisecondes, le frame a été considéré comme bloqué pour la gestion des entrées.

Indique si duration ou blockingDuration doit être examiné.

Pour l'affichage commun à 60 Hz, un navigateur tente de planifier un frame au moins toutes les 16,66 ms (pour assurer des mises à jour fluides) ou après une tâche de priorité élevée, comme la gestion des entrées (pour assurer des mises à jour réactives). Toutefois, si aucune entrée ni aucune autre tâche de priorité élevée n'est effectuée, mais qu'une file d'attente d'autres tâches est présente, le navigateur continue généralement le frame actuel bien au-delà de 16,66 millisecondes, quelle que soit la répartition des tâches. Autrement dit, le navigateur essaie toujours de prioriser les entrées, mais peut choisir de s'occuper d'une file d'attente de tâches plutôt que de mettre à jour le rendu. En effet, le rendu est un processus coûteux. Le traitement d'une tâche de rendu combinée pour plusieurs tâches entraîne généralement une réduction globale du travail.

Par conséquent, les images animées longues avec une blockingDuration faible ou nulle doivent toujours répondre aux entrées. Réduire ou éliminer les blockingDuration en divisant les tâches longues est donc essentiel pour améliorer la réactivité, telle que mesurée par l'INP.

Toutefois, de nombreux frames d'animation longs, quel que soit le paramètre blockingDuration, indiquent des mises à jour de l'UI retardées, ce qui peut toujours affecter la fluidité et donner l'impression d'une interface utilisateur lente pour le défilement ou les animations, même si ces éléments sont moins problématiques pour la réactivité mesurée par l'INP. Pour comprendre les problèmes dans ce domaine, examinez les duration. Toutefois, ceux-ci peuvent être plus difficiles à optimiser, car vous ne pouvez pas les résoudre en divisant le travail, mais en le réduisant.

Temps de rendu

Les codes temporels mentionnés précédemment permettent de diviser le frame d'animation long en codes temporels :

Durée Calcul
Heure de début startTime
Heure de fin startTime + duration
Durée de la tâche renderStart ? renderStart - startTime : duration
Durée du rendu renderStart ? (startTime + duration) - renderStart: 0
Rendu: durée de prémise en page styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Rendu: durée du style et de la mise en page styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Meilleure attribution des scripts

Le type d'entrée long-animation-frame inclut de meilleures données d'attribution pour chaque script ayant contribué à un frame d'animation long (pour les scripts de plus de cinq millisecondes).

Comme pour l'API Long Tasks, ces données seront fournies dans un tableau d'entrées d'attribution, chacune contenant les informations suivantes:

  • name et EntryType renvoient tous les deux script.
  • Un invoker significatif, indiquant comment le script a été appelé (par exemple, 'IMG#id.onload', 'Window.requestAnimationFrame' ou 'Response.json.then').
  • invokerType du point d'entrée du script :
    • user-callback : rappel connu enregistré à partir d'une API de plate-forme Web (par exemple, setTimeout, requestAnimationFrame).
    • event-listener: écouteur d'un événement de plate-forme (par exemple, click, load, keyup).
    • resolve-promise : gestionnaire d'une promesse de plate-forme (par exemple, fetch()). Notez que dans le cas des promesses, tous les gestionnaires des mêmes promesses sont mélangés dans un seul "script"..
    • reject-promise: conformément à resolve-promise, mais pour le refus.
    • classic-script : évaluation du script (par exemple, <script> ou import())
    • module-script: identique à classic-script, mais pour les scripts de module.
  • Données de synchronisation distinctes pour ce script :
    • startTime : heure à laquelle la fonction d'entrée a été appelée.
    • duration : durée entre startTime et la fin du traitement de la file de microtâches suivante.
    • executionStart: heure après la compilation.
    • forcedStyleAndLayoutDuration: temps total passé à traiter la mise en page et le style forcés dans cette fonction (voir thrashing).
    • pauseDuration : temps total passé à "mettre en pause" les opérations synchrones (alerte, XHR synchrone).
  • Détails de la source du script :
    • sourceURL : nom de la ressource de script, le cas échéant (ou vide si elle n'est pas trouvée).
    • sourceFunctionName : nom de la fonction de script, le cas échéant (ou vide si elle n'est pas trouvée).
    • sourceCharPosition : position du caractère du script, le cas échéant (ou -1 si aucun caractère n'est trouvé).
  • windowAttribution : conteneur (document de niveau supérieur ou <iframe>) dans lequel le frame d'animation long s'est produit.
  • window: référence à la fenêtre de même origine.

Le cas échéant, les entrées source permettent aux développeurs de savoir exactement comment chaque script du frame d'animation long a été appelé, jusqu'à la position du caractère dans le script appelant. Cela indique l'emplacement exact dans une ressource JavaScript qui a entraîné le long frame d'animation.

Exemple d'entrée de performances long-animation-frame

Voici un exemple complet d'entrée de performance long-animation-frame contenant un seul script:

{
  "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
}

Comme vous pouvez le constater, cela fournit aux sites Web une quantité de données sans précédent pour comprendre la cause des mises à jour de rendu lentes.

Utiliser l'API Long Animation Frames dans le champ

Des outils tels que Chrome DevTools et Lighthouse, bien qu'utiles pour découvrir et reproduire des problèmes, sont des outils de laboratoire qui peuvent manquer d'aspects importants de l'expérience utilisateur que seules les données sur le terrain peuvent fournir.

L'API Long Animation Frames est conçue pour être utilisée sur le terrain afin de collecter des données contextuelles importantes pour les interactions utilisateur que l'API Long Tasks ne pouvait pas. Cela peut vous aider à identifier et à reproduire les problèmes d'interactivité que vous n'auriez peut-être pas découverts autrement.

Prise en charge de la fonctionnalité de détection des frames d'animation longs avec l'API

Vous pouvez utiliser le code suivant pour vérifier si l'API est compatible :

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

Le cas d'utilisation le plus évident de l'API Long Animation Frames consiste à aider à diagnostiquer et à résoudre les problèmes d'Interaction to Next Paint (INP). C'est l'une des principales raisons pour lesquelles l'équipe Chrome a développé cette API. Un INP de qualité est celui où toutes les interactions sont traitées en 200 millisecondes ou moins, de l'interaction jusqu'à la peinture du frame. Étant donné que l'API Long Animation Frames mesure tous les frames qui prennent 50 ms ou plus, la plupart des INP problématiques doivent inclure des données LoAF pour vous aider à diagnostiquer ces interactions.

La "LoAF INP" est la LoAF qui inclut l'interaction INP, comme illustré dans le diagramme suivant :

Exemples de frames d&#39;animation longs sur une page, avec la durée d&#39;inactivité de l&#39;utilisateur mise en évidence.
Une page peut comporter de nombreuses LoAF, dont l'une est liée à l'interaction INP.

Dans certains cas, il est possible qu'un événement INP couvre deux LOAF, généralement si l'interaction se produit après que l'image a lancé la partie de rendu du frame précédent, et que le gestionnaire d'événements est donc traité dans l'image suivante:

Exemples de frames d&#39;animation longs sur une page, avec la durée d&#39;inactivité de l&#39;utilisateur mise en évidence.
Une page peut comporter de nombreux LOAF, dont l'un est lié à l'interaction INP.

Dans de rares cas, il est même possible qu'il couvre plus de deux LOAF.

Enregistrer les données des LoAF associées à l'interaction INP vous permet d'obtenir beaucoup plus d'informations sur l'interaction INP pour la diagnostiquer. Cela est particulièrement utile pour comprendre le délai d'entrée, car vous pouvez voir quels autres scripts étaient exécutés dans ce frame.

Il peut également être utile de comprendre les durées de traitement et retards de présentation inexpliquées si vos gestionnaires d'événements ne reproduisent pas les valeurs observées pour ces éléments, car d'autres scripts peuvent s'exécuter pour vos utilisateurs et ne pas être inclus dans vos propres tests.

Il n'existe aucune API directe permettant d'associer une entrée INP à une ou plusieurs entrées LoAF associées, mais vous pouvez le faire dans le code en comparant les heures de début et de fin de chacune (voir l'exemple de script WhyNp). La bibliothèque web-vitals inclut tous les LoAF qui se croisent dans la propriété longAnimationFramesEntries de l'interface d'attribution INP à partir de la version 4.

Une fois que vous avez associé l'entrée ou les entrées de la liste d'attente d'autorisation, vous pouvez inclure des informations avec une attribution INP. L'objet scripts contient certaines des informations les plus précieuses, car il peut indiquer ce qui s'exécute dans ces frames. Ainsi, en renvoyant ces données à votre service d'analyse, vous pourrez mieux comprendre pourquoi les interactions étaient lentes.

Signaler les erreurs de non-fonctionnement pour l'interaction INP est un bon moyen de trouver les problèmes d'interactivité les plus urgents sur votre page. Chaque utilisateur peut interagir différemment avec votre page. Si vous disposez d'un volume suffisant de données d'attribution par INP, un certain nombre de problèmes potentiels seront inclus dans ces données. Vous pouvez ainsi trier les scripts par volume pour voir ceux qui sont associés à une vitesse d'importation des données lentes.

Signaler des données d'animation plus longues à un point de terminaison d'analyse

L'inconvénient de ne regarder que les avertissements de non-conformité de l'INP est que vous risquez de passer à côté d'autres axes d'amélioration potentiels qui pourraient entraîner des problèmes d'INP à l'avenir. Vous pouvez alors avoir l'impression de tourner en rond. Vous corrigez un problème d'INP en vous attendant à une amélioration considérable, mais vous constatez que l'interaction la plus lente suivante n'est que légèrement meilleure, ce qui n'améliore pas beaucoup votre INP.

Plutôt que de vous concentrer uniquement sur la métrique LoAF de l'INP, vous pouvez envisager de prendre en compte toutes les métriques LoAF sur la durée de vie de la page :

Page comportant de nombreuses erreurs de chargement hors connexion, dont certaines se produisent lors d&#39;interactions, même si elles ne sont pas liées à l&#39;interaction INP.
Examiner toutes les erreurs de localisation de l'utilisateur peut vous aider à identifier les futurs problèmes liés à l'INP.

Cependant, chaque entrée LoAF contient énormément de données, il est donc probable que vous souhaitiez limiter votre analyse à certains d'entre eux uniquement. De plus, comme les entrées de cadres d'animation longues peuvent être très volumineuses, les développeurs doivent décider quelles données de l'entrée doivent être envoyées à l'analyse. Par exemple, les heures récapitulatives de l'entrée et peut-être les noms des scripts, ou tout autre ensemble minimal d'autres données contextuelles pouvant être jugées nécessaires.

Voici quelques suggestions pour réduire la quantité de données de longues images d'animation:

Le modèle qui vous convient le mieux dépend de votre niveau d'optimisation et de la fréquence des images d'animation longues. Pour un site qui n'a jamais été optimisé pour la réactivité auparavant, il peut y avoir de nombreuses erreurs de chargement lent. Vous pouvez donc vous limiter aux erreurs de chargement lent avec interactions, définir un seuil élevé ou n'examiner que les plus graves.

À mesure que vous résoudrez les problèmes de réactivité courants, vous pouvez étendre cette fonctionnalité en ne vous limitant pas aux interactions ou aux durées de blocage élevées, ou en réduisant les seuils.

Observer les frames d'animation longs avec des interactions

Pour obtenir des insights au-delà de la longue image d'animation INP, vous pouvez examiner tous les LOAF avec des interactions (qui peuvent être détectées par la présence d'une valeur firstUIEventTimestamp) avec une blockingDuration élevée.

Il peut également s'agir d'une méthode plus simple pour surveiller les enregistrements de l'INP plutôt que d'essayer de les mettre en corrélation, ce qui peut être plus complexe. Dans la plupart des cas, cela inclut l'INP hors connexion pour une visite donnée. Dans de rares cas, il n'en est pas ainsi, mais des interactions longues qui doivent être corrigées sont tout de même détectées, car elles peuvent être l'interaction INP pour d'autres utilisateurs.

Le code suivant consigne toutes les entrées LoAF avec un blockingDuration supérieur à 100 millisecondes où une interaction s'est produite pendant le frame. Le nombre 100 est choisi ici, car il est inférieur au seuil d'INP "bon" de 200 ms. Vous pouvez choisir une valeur plus élevée ou plus faible en fonction de vos besoins.

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 });

Observer des cadres d'animation longs avec des durées de blocage élevées

Au lieu d'examiner tous les frames d'animation longs avec des interactions, vous pouvez examiner tous les frames d'animation longs avec des durées de blocage élevées. Ils indiquent des problèmes potentiels d'entrée utilisateur si un utilisateur interagit pendant ces longs frames d'animation.

Le code suivant consigne toutes les entrées LoAF dont la durée de blocage est supérieure à 100 millisecondes et pour lesquelles une interaction s'est produite pendant le frame. La valeur 100 est choisie ici, car elle est inférieure au seuil d'INP "bon" de 200 millisecondes pour aider à identifier les images problématiques potentielles, tout en limitant au minimum le nombre d'images d'animation longues signalées. Vous pouvez choisir une valeur plus élevée ou plus faible en fonction de vos besoins.

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 });

Observer les longs frames d'animation lors des mises à jour critiques de l'UI pour améliorer la fluidité

Comme indiqué précédemment, examiner les frames d'animation longs à durée de blocage élevée peut vous aider à améliorer la réactivité des entrées. Toutefois, pour une fluidité optimale, vous devez examiner tous les frames d'animation longs avec un duration long.

Comme cela peut générer beaucoup de bruit, vous pouvez limiter les mesures de ces valeurs aux points clés en utilisant un modèle comme celui-ci:

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;
}

Observer les pires frames d'animation longue

Plutôt que de définir un seuil, les sites peuvent choisir de collecter des données sur le ou les frames d'animation les plus longs afin de réduire le volume de données à diffuser par balise. Ainsi, quel que soit le nombre de longues animations affichées sur une page, seules les données correspondant au pire, cinq, dix ou le nombre de longues animations absolument nécessaires sont renvoyées.

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 });

Ces stratégies peuvent également être combinées : vous ne pouvez examiner que les 10 manchots de faible niveau d'engagement de plus de 100 millisecondes, avec des interactions de plus de 100 millisecondes.

Au moment opportun (idéalement lors de l'événement visibilitychange), le balise renvoie les données à Analytics. Pour les tests en local, vous pouvez utiliser régulièrement console.table:

console.table(longestBlockingLoAFs);

Identifier les modèles courants dans les images animées longues

Une autre stratégie consiste à examiner les scripts courants qui apparaissent le plus souvent dans les entrées de frames d'animation longues. Les données peuvent être rapportées au niveau du script et de la position des personnages afin d'identifier les responsables d'infractions répétées.

Cette approche peut être particulièrement efficace pour les plates-formes personnalisables, où les thèmes ou les plug-ins à l'origine de problèmes de performances peuvent être identifiés sur plusieurs sites.

Le temps d'exécution des scripts courants (ou des origines tierces) dans les frames d'animation longs peut être résumé et signalé pour identifier les contributeurs courants aux frames d'animation longs sur un site ou un ensemble de sites. Par exemple, pour consulter les URL:

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});

Voici un exemple de résultat:

(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

Utiliser l'API Long Animation Frames dans les outils

L'API permet également d'utiliser des outils de développement supplémentaires pour le débogage local. Bien que certains outils tels que Lighthouse et Chrome DevTools aient pu collecter une grande partie de ces données à l'aide de détails de traçage de bas niveau, la présence de cette API de niveau supérieur pourrait permettre à d'autres outils d'accéder à ces données.

Afficher les données des longues frames d'animation dans les outils de développement

Vous pouvez afficher des frames d'animation longs dans DevTools à l'aide de l'API performance.measure(), qui sont ensuite affichés dans la piste de temps utilisateur DevTools dans les traces de performances pour vous indiquer où concentrer vos efforts afin d'améliorer les performances. Grâce à l'API d'extensibilité DevTools, vous pouvez même les afficher dans leur propre canal:

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 });
Trace du panneau &quot;Performances&quot; des outils de développement avec une piste personnalisée affichant les données du frame d&#39;animation long, qui peuvent être comparées au graphique de flammes principal.
Affichage des données sur les longues frames d'animation dans les outils de développement

À plus long terme, les frames d'animation longs seront probablement intégrés aux outils pour les développeurs eux-mêmes, mais l'extrait de code précédent permet de les afficher en attendant.

La première entrée de la figure précédente montre également où le navigateur a traité plusieurs tâches ensemble dans le même frame d'animation long au lieu de les afficher entre elles. Comme indiqué précédemment, cela peut se produire lorsqu'il n'y a pas de tâches d'entrée à priorité élevée, mais qu'il existe une file d'attente de tâches. La première tâche longue doit effectuer des mises à jour de rendu (sinon, le frame d'animation long actuel serait réinitialisé après, et un nouveau commencerait avec la tâche suivante). Toutefois, au lieu d'exécuter immédiatement ce rendu, le navigateur a traité un certain nombre de tâches supplémentaires, puis seulement exécuté la tâche de rendu longue et mis fin au frame d'animation long. Cela montre l'utilité d'examiner les frames d'animation longs dans les outils de développement, plutôt que de se contenter de tâches longues, pour identifier les rendus retardés.

Utiliser les données des frames d'animation longues dans d'autres outils de développement

L'extension Web Vitals a affiché la valeur dans les informations de débogage du résumé de journalisation pour diagnostiquer les problèmes de performances.

Désormais, il affiche également de longues données d'images d'animation pour chaque rappel INP et chaque interaction:

Journalisation de la console de l&#39;extension Web Vitals.
La journalisation de la console de l'extension Web Vitals affiche les données LoAF.

Utiliser les données des frames d'animation longues dans les outils de test automatisés

De même, les outils de test automatisés des pipelines CI/CD peuvent fournir des informations sur les problèmes de performances potentiels en mesurant les frames d'animation longs lors de l'exécution de diverses suites de tests.

Questions fréquentes

Voici quelques questions fréquentes sur cette API :

Pourquoi ne pas simplement étendre ou itérer sur l'API Long Tasks ?

Il s'agit d'une autre façon de mesurer les problèmes de réactivité potentiels, même si la mesure est similaire. Il est important de s'assurer que les sites qui dépendent de l'API Long Tasks existante continuent de fonctionner pour éviter de perturber les cas d'utilisation existants.

Bien que l'API Long Tasks puisse bénéficier de certaines fonctionnalités de LoAF (comme un meilleur modèle d'attribution), nous pensons que se concentrer sur les frames plutôt que sur les tâches offre de nombreux avantages qui font de cette API une API fondamentalement différente de l'API Long Tasks existante.

Why do I not have script entries?

Cela peut indiquer que le frame d'animation long n'était pas dû à JavaScipt, mais à un travail de rendu important.

Cela peut également se produire lorsque le frame d'animation long est dû à JavaScript, mais que l'attribution du script ne peut pas être fournie pour diverses raisons de confidentialité, comme indiqué précédemment (principalement parce que le code JavaScript n'appartient pas à la page).

Pourquoi y a-t-il des entrées de script, mais aucune information source ou des informations limitées ?

Cela peut se produire pour plusieurs raisons, y compris si aucune source appropriée n'est disponible.

Les informations sur les scripts seront également limitées pour les scripts no-cors cross-origin. Toutefois, vous pouvez résoudre ce problème en extrayant ces scripts à l'aide de CORS en ajoutant crossOrigin = "anonymous" à l'appel <script>.

Par exemple, voici le script Google Tag Manager par défaut à ajouter à la page:

<!-- 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 -->

Il peut être amélioré pour ajouter des j.crossOrigin = "anonymous" afin de permettre de fournir tous les détails de l'attribution pour GTM.

Cette API remplacera-t-elle l'API Long Tasks ?

Nous pensons que l'API Long Animation Frames est une API plus performante et plus complète pour mesurer les longues tâches. Toutefois, nous ne prévoyons pas d'abandonner l'API Long Tasks pour le moment.

Commentaires souhaités

Vous pouvez envoyer vos commentaires sur la liste des problèmes GitHub ou signaler les bugs dans l'implémentation de l'API dans Chrome dans le outil de suivi des problèmes de Chrome.

Conclusion

L'API Long Animation Frames est une nouvelle API intéressante qui présente de nombreux avantages potentiels par rapport à l'ancienne API Long Tasks.

Il s’avère qu’il s’agit d’un outil clé pour résoudre les problèmes de réactivité tels que mesurés par INP. L'INP est une métrique difficile à optimiser. L'équipe Chrome cherche à faciliter l'identification et la résolution des problèmes grâce à cette API.

L'API Long Animation Frames ne se limite pas aux INP. Elle peut vous aider à identifier d'autres causes de mises à jour lentes qui peuvent affecter la fluidité globale de l'expérience utilisateur d'un site Web.

Remerciements

Image de vignette par Henry Be sur Unsplash.